[][PATCH 1/4: phy-mtk-tphy: support type switch by pericfg]

[Description]
Add support type switch between USB3, PCIe, SATA and SGMII by pericfg
register, this is used to take the place of efuse or jumper.
this patch provides one solution to slove shareing mediatek phy design
for example: MT7981

[Release-log]
N/A

Change-Id: I69bf275a04f436da462b52f8f11d52da5e5af049
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5018452
diff --git a/target/linux/mediatek/patches-5.4/8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch b/target/linux/mediatek/patches-5.4/8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch
new file mode 100644
index 0000000..4ae4991
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch
@@ -0,0 +1,168 @@
+From ddeda571f3d79dcccef6541b6413cb184de40afd Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Fri, 17 Sep 2021 15:56:53 +0800
+Subject: [PATCH] phy: phy-mtk-tphy: support type switch by pericfg
+
+Add support type switch between USB3, PCIe, SATA and SGMII by
+pericfg register, this is used to take the place of efuse or
+jumper.
+
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 84 +++++++++++++++++++++++++++--
+ 1 file changed, 81 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index d1ecf088032b..759e1c0c370a 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -10,12 +10,12 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+-#include <linux/mfd/syscon.h>
+ #include <linux/regmap.h>
+ 
+ /* version V1 sub-banks offset base address */
+@@ -268,6 +268,14 @@
+ #define HIF_SYSCFG1			0x14
+ #define HIF_SYSCFG1_PHY2_MASK		(0x3 << 20)
+ 
++/* PHY switch between pcie/usb3/sgmii/sata */
++#define USB_PHY_SWITCH_CTRL	0x0
++#define RG_PHY_SW_TYPE		GENMASK(3, 0)
++#define RG_PHY_SW_PCIE		0x0
++#define RG_PHY_SW_USB3		0x1
++#define RG_PHY_SW_SGMII		0x2
++#define RG_PHY_SW_SATA		0x3
++
+ enum mtk_phy_version {
+ 	MTK_PHY_V1 = 1,
+ 	MTK_PHY_V2,
+@@ -301,7 +309,10 @@ struct mtk_phy_instance {
+ 	};
+ 	struct clk *ref_clk;	/* reference clock of anolog phy */
+ 	u32 index;
+-	u8 type;
++	u32 type;
++	struct regmap *type_sw;
++	u32 type_sw_reg;
++	u32 type_sw_index;
+ 	int eye_src;
+ 	int eye_vrt;
+ 	int eye_term;
+@@ -900,6 +911,64 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
+ 	}
+ }
+ 
++/* type switch for usb3/pcie/sgmii/sata */
++static int phy_type_syscon_get(struct mtk_phy_instance *instance,
++			       struct device_node *dn)
++{
++	struct of_phandle_args args;
++	int ret;
++
++	/* type switch function is optional */
++	if (!of_property_read_bool(dn, "mediatek,syscon-type"))
++		return 0;
++
++	ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
++					       2, 0, &args);
++	if (ret)
++		return ret;
++
++	instance->type_sw_reg = args.args[0];
++	instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
++	instance->type_sw = syscon_node_to_regmap(args.np);
++	of_node_put(args.np);
++	dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
++		 instance->type_sw_reg, instance->type_sw_index);
++
++	return PTR_ERR_OR_ZERO(instance->type_sw);
++}
++
++static int phy_type_set(struct mtk_phy_instance *instance)
++{
++	int type;
++	u32 mask;
++
++	if (!instance->type_sw)
++		return 0;
++
++	switch (instance->type) {
++	case PHY_TYPE_USB3:
++		type = RG_PHY_SW_USB3;
++		break;
++	case PHY_TYPE_PCIE:
++		type = RG_PHY_SW_PCIE;
++		break;
++	case PHY_TYPE_SGMII:
++		type = RG_PHY_SW_SGMII;
++		break;
++	case PHY_TYPE_SATA:
++		type = RG_PHY_SW_SATA;
++		break;
++	case PHY_TYPE_USB2:
++	default:
++		return 0;
++	}
++
++	mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE);
++	regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type);
++
++	return 0;
++}
++
+ static int mtk_phy_init(struct phy *phy)
+ {
+ 	struct mtk_phy_instance *instance = phy_get_drvdata(phy);
+@@ -932,6 +1001,9 @@ static int mtk_phy_init(struct phy *phy)
+ 	case PHY_TYPE_SATA:
+ 		sata_phy_instance_init(tphy, instance);
+ 		break;
++	case PHY_TYPE_SGMII:
++		/* nothing to do, only used to set type */
++		break;
+ 	default:
+ 		dev_err(tphy->dev, "incompatible PHY type\n");
+ 		return -EINVAL;
+@@ -1020,7 +1092,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 	if (!(instance->type == PHY_TYPE_USB2 ||
+ 	      instance->type == PHY_TYPE_USB3 ||
+ 	      instance->type == PHY_TYPE_PCIE ||
+-	      instance->type == PHY_TYPE_SATA)) {
++	      instance->type == PHY_TYPE_SATA ||
++	      instance->type == PHY_TYPE_SGMII)) {
+ 		dev_err(dev, "unsupported device type: %d\n", instance->type);
+ 		return ERR_PTR(-EINVAL);
+ 	}
+@@ -1035,6 +1108,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 	}
+ 
+ 	phy_parse_property(tphy, instance);
++	phy_type_set(instance);
+ 
+ 	return instance->phy;
+ }
+@@ -1183,6 +1257,10 @@ static int mtk_tphy_probe(struct platform_device *pdev)
+ 			retval = PTR_ERR(instance->ref_clk);
+ 			goto put_child;
+ 		}
++
++		retval = phy_type_syscon_get(instance, child_np);
++		if (retval)
++			goto put_child;
+ 	}
+ 
+ 	provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
+-- 
+2.18.0
+