blob: c20e93083e0672bd9ca83a59fd5352aa76dce2e5 [file] [log] [blame]
developer2cdaeb12022-10-04 20:25:05 +08001diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c
2index 8c51131..e77092c 100644
3--- a/drivers/phy/mediatek/phy-mtk-xsphy.c
4+++ b/drivers/phy/mediatek/phy-mtk-xsphy.c
5@@ -12,10 +12,12 @@
6 #include <linux/delay.h>
7 #include <linux/io.h>
8 #include <linux/iopoll.h>
9+#include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/of_address.h>
12 #include <linux/phy/phy.h>
13 #include <linux/platform_device.h>
14+#include <linux/regmap.h>
15
16 /* u2 phy banks */
17 #define SSUSB_SIFSLV_MISC 0x000
18@@ -88,12 +90,22 @@
19 #define XSP_SR_COEF_DIVISOR 1000
20 #define XSP_FM_DET_CYCLE_CNT 1024
21
22+/* PHY switch between pcie/usb3/sgmii */
23+#define USB_PHY_SWITCH_CTRL 0x0
24+#define RG_PHY_SW_TYPE GENMASK(3, 0)
25+#define RG_PHY_SW_PCIE 0x0
26+#define RG_PHY_SW_USB3 0x1
27+#define RG_PHY_SW_SGMII 0x2
28+
29 struct xsphy_instance {
30 struct phy *phy;
31 void __iomem *port_base;
32 struct clk *ref_clk; /* reference clock of anolog phy */
33 u32 index;
34 u32 type;
35+ struct regmap *type_sw;
36+ u32 type_sw_reg;
37+ u32 type_sw_index;
38 /* only for HQA test */
39 int efuse_intr;
40 int efuse_tx_imp;
41@@ -365,6 +377,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy,
42 }
43 }
44
45+/* type switch for usb3/pcie/sgmii */
46+static int phy_type_syscon_get(struct xsphy_instance *instance,
47+ struct device_node *dn)
48+{
49+ struct of_phandle_args args;
50+ int ret;
51+
52+ /* type switch function is optional */
53+ if (!of_property_read_bool(dn, "mediatek,syscon-type"))
54+ return 0;
55+
56+ ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
57+ 2, 0, &args);
58+ if (ret)
59+ return ret;
60+
61+ instance->type_sw_reg = args.args[0];
62+ instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
63+ instance->type_sw = syscon_node_to_regmap(args.np);
64+ of_node_put(args.np);
65+ dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
66+ instance->type_sw_reg, instance->type_sw_index);
67+
68+ return PTR_ERR_OR_ZERO(instance->type_sw);
69+}
70+
71+static int phy_type_set(struct xsphy_instance *instance)
72+{
73+ int type;
74+ u32 offset;
75+
76+ if (!instance->type_sw)
77+ return 0;
78+
79+ switch (instance->type) {
80+ case PHY_TYPE_USB3:
81+ type = RG_PHY_SW_USB3;
82+ break;
83+ case PHY_TYPE_PCIE:
84+ type = RG_PHY_SW_PCIE;
85+ break;
86+ case PHY_TYPE_SGMII:
87+ type = RG_PHY_SW_SGMII;
88+ break;
89+ case PHY_TYPE_USB2:
90+ default:
91+ return 0;
92+ }
93+
94+ offset = instance->type_sw_index * BITS_PER_BYTE;
95+ regmap_update_bits(instance->type_sw, instance->type_sw_reg,
96+ RG_PHY_SW_TYPE << offset, type << offset);
97+
98+ return 0;
99+}
100+
101 static int mtk_phy_init(struct phy *phy)
102 {
103 struct xsphy_instance *inst = phy_get_drvdata(phy);
104@@ -385,6 +453,10 @@ static int mtk_phy_init(struct phy *phy)
105 case PHY_TYPE_USB3:
106 u3_phy_props_set(xsphy, inst);
107 break;
108+ case PHY_TYPE_PCIE:
109+ case PHY_TYPE_SGMII:
110+ /* nothing to do, only used to set type */
111+ break;
112 default:
113 dev_err(xsphy->dev, "incompatible phy type\n");
114 clk_disable_unprepare(inst->ref_clk);
115@@ -463,12 +535,15 @@ static struct phy *mtk_phy_xlate(struct device *dev,
116
117 inst->type = args->args[0];
118 if (!(inst->type == PHY_TYPE_USB2 ||
119- inst->type == PHY_TYPE_USB3)) {
120+ inst->type == PHY_TYPE_USB3 ||
121+ inst->type == PHY_TYPE_PCIE ||
122+ inst->type == PHY_TYPE_SGMII)) {
123 dev_err(dev, "unsupported phy type: %d\n", inst->type);
124 return ERR_PTR(-EINVAL);
125 }
126
127 phy_parse_property(xsphy, inst);
128+ phy_type_set(inst);
129
130 return inst->phy;
131 }
132@@ -575,6 +650,10 @@ static int mtk_xsphy_probe(struct platform_device *pdev)
133 retval = PTR_ERR(inst->ref_clk);
134 goto put_child;
135 }
136+
137+ retval = phy_type_syscon_get(inst, child_np);
138+ if (retval)
139+ goto put_child;
140 }
141
142 provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);