mediatek: copy patches-6.1 to patches-6.6
[openwrt/staging/stintel.git] / target / linux / mediatek / patches-6.6 / 615-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch
1 From 50cefacc6c001eea1d9b1c78ba27304566f304f1 Mon Sep 17 00:00:00 2001
2 From: Daniel Golle <daniel@makrotopia.org>
3 Date: Fri, 2 Jun 2023 13:06:26 +0800
4 Subject: [PATCH] phy: mediatek: xsphy: support type switch by pericfg
5
6 Patch from Sam Shih <sam.shih@mediatek.com> found in MediaTek SDK
7 released under GPL.
8
9 Get syscon and use it to set the PHY type.
10 Extend support to PCIe and SGMII mode in addition to USB2 and USB3.
11
12 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
13 ---
14 drivers/phy/mediatek/phy-mtk-xsphy.c | 81 +++++++++++++++++++++++++++-
15 1 file changed, 80 insertions(+), 1 deletion(-)
16
17 --- a/drivers/phy/mediatek/phy-mtk-xsphy.c
18 +++ b/drivers/phy/mediatek/phy-mtk-xsphy.c
19 @@ -11,10 +11,12 @@
20 #include <linux/clk.h>
21 #include <linux/delay.h>
22 #include <linux/iopoll.h>
23 +#include <linux/mfd/syscon.h>
24 #include <linux/module.h>
25 #include <linux/of_address.h>
26 #include <linux/phy/phy.h>
27 #include <linux/platform_device.h>
28 +#include <linux/regmap.h>
29
30 #include "phy-mtk-io.h"
31
32 @@ -81,12 +83,22 @@
33 #define XSP_SR_COEF_DIVISOR 1000
34 #define XSP_FM_DET_CYCLE_CNT 1024
35
36 +/* PHY switch between pcie/usb3/sgmii */
37 +#define USB_PHY_SWITCH_CTRL 0x0
38 +#define RG_PHY_SW_TYPE GENMASK(3, 0)
39 +#define RG_PHY_SW_PCIE 0x0
40 +#define RG_PHY_SW_USB3 0x1
41 +#define RG_PHY_SW_SGMII 0x2
42 +
43 struct xsphy_instance {
44 struct phy *phy;
45 void __iomem *port_base;
46 struct clk *ref_clk; /* reference clock of anolog phy */
47 u32 index;
48 u32 type;
49 + struct regmap *type_sw;
50 + u32 type_sw_reg;
51 + u32 type_sw_index;
52 /* only for HQA test */
53 int efuse_intr;
54 int efuse_tx_imp;
55 @@ -259,6 +271,10 @@ static void phy_parse_property(struct mt
56 inst->efuse_intr, inst->efuse_tx_imp,
57 inst->efuse_rx_imp);
58 break;
59 + case PHY_TYPE_PCIE:
60 + case PHY_TYPE_SGMII:
61 + /* nothing to do */
62 + break;
63 default:
64 dev_err(xsphy->dev, "incompatible phy type\n");
65 return;
66 @@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_
67 RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp);
68 }
69
70 +/* type switch for usb3/pcie/sgmii */
71 +static int phy_type_syscon_get(struct xsphy_instance *instance,
72 + struct device_node *dn)
73 +{
74 + struct of_phandle_args args;
75 + int ret;
76 +
77 + /* type switch function is optional */
78 + if (!of_property_read_bool(dn, "mediatek,syscon-type"))
79 + return 0;
80 +
81 + ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
82 + 2, 0, &args);
83 + if (ret)
84 + return ret;
85 +
86 + instance->type_sw_reg = args.args[0];
87 + instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
88 + instance->type_sw = syscon_node_to_regmap(args.np);
89 + of_node_put(args.np);
90 + dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
91 + instance->type_sw_reg, instance->type_sw_index);
92 +
93 + return PTR_ERR_OR_ZERO(instance->type_sw);
94 +}
95 +
96 +static int phy_type_set(struct xsphy_instance *instance)
97 +{
98 + int type;
99 + u32 offset;
100 +
101 + if (!instance->type_sw)
102 + return 0;
103 +
104 + switch (instance->type) {
105 + case PHY_TYPE_USB3:
106 + type = RG_PHY_SW_USB3;
107 + break;
108 + case PHY_TYPE_PCIE:
109 + type = RG_PHY_SW_PCIE;
110 + break;
111 + case PHY_TYPE_SGMII:
112 + type = RG_PHY_SW_SGMII;
113 + break;
114 + case PHY_TYPE_USB2:
115 + default:
116 + return 0;
117 + }
118 +
119 + offset = instance->type_sw_index * BITS_PER_BYTE;
120 + regmap_update_bits(instance->type_sw, instance->type_sw_reg,
121 + RG_PHY_SW_TYPE << offset, type << offset);
122 +
123 + return 0;
124 +}
125 +
126 static int mtk_phy_init(struct phy *phy)
127 {
128 struct xsphy_instance *inst = phy_get_drvdata(phy);
129 @@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy)
130 case PHY_TYPE_USB3:
131 u3_phy_props_set(xsphy, inst);
132 break;
133 + case PHY_TYPE_PCIE:
134 + case PHY_TYPE_SGMII:
135 + /* nothing to do, only used to set type */
136 + break;
137 default:
138 dev_err(xsphy->dev, "incompatible phy type\n");
139 clk_disable_unprepare(inst->ref_clk);
140 @@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct
141
142 inst->type = args->args[0];
143 if (!(inst->type == PHY_TYPE_USB2 ||
144 - inst->type == PHY_TYPE_USB3)) {
145 + inst->type == PHY_TYPE_USB3 ||
146 + inst->type == PHY_TYPE_PCIE ||
147 + inst->type == PHY_TYPE_SGMII)) {
148 dev_err(dev, "unsupported phy type: %d\n", inst->type);
149 return ERR_PTR(-EINVAL);
150 }
151
152 phy_parse_property(xsphy, inst);
153 + phy_type_set(inst);
154
155 return inst->phy;
156 }
157 @@ -515,6 +594,10 @@ static int mtk_xsphy_probe(struct platfo
158 retval = PTR_ERR(inst->ref_clk);
159 goto put_child;
160 }
161 +
162 + retval = phy_type_syscon_get(inst, child_np);
163 + if (retval)
164 + goto put_child;
165 }
166
167 provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);