This source file includes following definitions.
- mvebu_a3700_comphy_smc
- mvebu_a3700_comphy_get_fw_mode
- mvebu_a3700_comphy_set_mode
- mvebu_a3700_comphy_power_on
- mvebu_a3700_comphy_power_off
- mvebu_a3700_comphy_xlate
- mvebu_a3700_comphy_probe
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/arm-smccc.h>
14 #include <linux/io.h>
15 #include <linux/iopoll.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/module.h>
18 #include <linux/phy.h>
19 #include <linux/phy/phy.h>
20 #include <linux/platform_device.h>
21
22 #define MVEBU_A3700_COMPHY_LANES 3
23 #define MVEBU_A3700_COMPHY_PORTS 2
24
25
26 #define COMPHY_SIP_POWER_ON 0x82000001
27 #define COMPHY_SIP_POWER_OFF 0x82000002
28 #define COMPHY_SIP_PLL_LOCK 0x82000003
29 #define COMPHY_FW_NOT_SUPPORTED (-1)
30
31 #define COMPHY_FW_MODE_SATA 0x1
32 #define COMPHY_FW_MODE_SGMII 0x2
33 #define COMPHY_FW_MODE_HS_SGMII 0x3
34 #define COMPHY_FW_MODE_USB3H 0x4
35 #define COMPHY_FW_MODE_USB3D 0x5
36 #define COMPHY_FW_MODE_PCIE 0x6
37 #define COMPHY_FW_MODE_RXAUI 0x7
38 #define COMPHY_FW_MODE_XFI 0x8
39 #define COMPHY_FW_MODE_SFI 0x9
40 #define COMPHY_FW_MODE_USB3 0xa
41
42 #define COMPHY_FW_SPEED_1_25G 0
43 #define COMPHY_FW_SPEED_2_5G 1
44 #define COMPHY_FW_SPEED_3_125G 2
45 #define COMPHY_FW_SPEED_5G 3
46 #define COMPHY_FW_SPEED_5_15625G 4
47 #define COMPHY_FW_SPEED_6G 5
48 #define COMPHY_FW_SPEED_10_3125G 6
49 #define COMPHY_FW_SPEED_MAX 0x3F
50
51 #define COMPHY_FW_MODE(mode) ((mode) << 12)
52 #define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \
53 ((idx) << 8) | \
54 ((speed) << 2))
55 #define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \
56 ((width) << 18))
57
58 struct mvebu_a3700_comphy_conf {
59 unsigned int lane;
60 enum phy_mode mode;
61 int submode;
62 unsigned int port;
63 u32 fw_mode;
64 };
65
66 #define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \
67 { \
68 .lane = _lane, \
69 .mode = _mode, \
70 .submode = _smode, \
71 .port = _port, \
72 .fw_mode = _fw, \
73 }
74
75 #define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \
76 MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw)
77
78 #define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \
79 MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw)
80
81 static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = {
82
83 MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0,
84 COMPHY_FW_MODE_USB3H),
85 MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1,
86 COMPHY_FW_MODE_SGMII),
87 MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1,
88 COMPHY_FW_MODE_HS_SGMII),
89
90 MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0,
91 COMPHY_FW_MODE_PCIE),
92 MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0,
93 COMPHY_FW_MODE_SGMII),
94 MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0,
95 COMPHY_FW_MODE_HS_SGMII),
96
97 MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0,
98 COMPHY_FW_MODE_SATA),
99 MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0,
100 COMPHY_FW_MODE_USB3H),
101 };
102
103 struct mvebu_a3700_comphy_lane {
104 struct device *dev;
105 unsigned int id;
106 enum phy_mode mode;
107 int submode;
108 int port;
109 };
110
111 static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
112 unsigned long mode)
113 {
114 struct arm_smccc_res res;
115
116 arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res);
117
118 return res.a0;
119 }
120
121 static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
122 enum phy_mode mode,
123 int submode)
124 {
125 int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes);
126
127
128 if (mode == PHY_MODE_INVALID)
129 return -EINVAL;
130
131 for (i = 0; i < n; i++) {
132 if (mvebu_a3700_comphy_modes[i].lane == lane &&
133 mvebu_a3700_comphy_modes[i].port == port &&
134 mvebu_a3700_comphy_modes[i].mode == mode &&
135 mvebu_a3700_comphy_modes[i].submode == submode)
136 break;
137 }
138
139 if (i == n)
140 return -EINVAL;
141
142 return mvebu_a3700_comphy_modes[i].fw_mode;
143 }
144
145 static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode,
146 int submode)
147 {
148 struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
149 int fw_mode;
150
151 if (submode == PHY_INTERFACE_MODE_1000BASEX)
152 submode = PHY_INTERFACE_MODE_SGMII;
153
154 fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode,
155 submode);
156 if (fw_mode < 0) {
157 dev_err(lane->dev, "invalid COMPHY mode\n");
158 return fw_mode;
159 }
160
161
162 lane->mode = mode;
163 lane->submode = submode;
164
165 return 0;
166 }
167
168 static int mvebu_a3700_comphy_power_on(struct phy *phy)
169 {
170 struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
171 u32 fw_param;
172 int fw_mode;
173 int ret;
174
175 fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port,
176 lane->mode, lane->submode);
177 if (fw_mode < 0) {
178 dev_err(lane->dev, "invalid COMPHY mode\n");
179 return fw_mode;
180 }
181
182 switch (lane->mode) {
183 case PHY_MODE_USB_HOST_SS:
184 dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id);
185 fw_param = COMPHY_FW_MODE(fw_mode);
186 break;
187 case PHY_MODE_SATA:
188 dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id);
189 fw_param = COMPHY_FW_MODE(fw_mode);
190 break;
191 case PHY_MODE_ETHERNET:
192 switch (lane->submode) {
193 case PHY_INTERFACE_MODE_SGMII:
194 dev_dbg(lane->dev, "set lane %d to SGMII mode\n",
195 lane->id);
196 fw_param = COMPHY_FW_NET(fw_mode, lane->port,
197 COMPHY_FW_SPEED_1_25G);
198 break;
199 case PHY_INTERFACE_MODE_2500BASEX:
200 dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n",
201 lane->id);
202 fw_param = COMPHY_FW_NET(fw_mode, lane->port,
203 COMPHY_FW_SPEED_3_125G);
204 break;
205 default:
206 dev_err(lane->dev, "unsupported PHY submode (%d)\n",
207 lane->submode);
208 return -ENOTSUPP;
209 }
210 break;
211 case PHY_MODE_PCIE:
212 dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id);
213 fw_param = COMPHY_FW_PCIE(fw_mode, lane->port,
214 COMPHY_FW_SPEED_5G,
215 phy->attrs.bus_width);
216 break;
217 default:
218 dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode);
219 return -ENOTSUPP;
220 }
221
222 ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
223 if (ret == COMPHY_FW_NOT_SUPPORTED)
224 dev_err(lane->dev,
225 "unsupported SMC call, try updating your firmware\n");
226
227 return ret;
228 }
229
230 static int mvebu_a3700_comphy_power_off(struct phy *phy)
231 {
232 struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
233
234 return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0);
235 }
236
237 static const struct phy_ops mvebu_a3700_comphy_ops = {
238 .power_on = mvebu_a3700_comphy_power_on,
239 .power_off = mvebu_a3700_comphy_power_off,
240 .set_mode = mvebu_a3700_comphy_set_mode,
241 .owner = THIS_MODULE,
242 };
243
244 static struct phy *mvebu_a3700_comphy_xlate(struct device *dev,
245 struct of_phandle_args *args)
246 {
247 struct mvebu_a3700_comphy_lane *lane;
248 struct phy *phy;
249
250 if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS))
251 return ERR_PTR(-EINVAL);
252
253 phy = of_phy_simple_xlate(dev, args);
254 if (IS_ERR(phy))
255 return phy;
256
257 lane = phy_get_drvdata(phy);
258 lane->port = args->args[0];
259
260 return phy;
261 }
262
263 static int mvebu_a3700_comphy_probe(struct platform_device *pdev)
264 {
265 struct phy_provider *provider;
266 struct device_node *child;
267
268 for_each_available_child_of_node(pdev->dev.of_node, child) {
269 struct mvebu_a3700_comphy_lane *lane;
270 struct phy *phy;
271 int ret;
272 u32 lane_id;
273
274 ret = of_property_read_u32(child, "reg", &lane_id);
275 if (ret < 0) {
276 dev_err(&pdev->dev, "missing 'reg' property (%d)\n",
277 ret);
278 continue;
279 }
280
281 if (lane_id >= MVEBU_A3700_COMPHY_LANES) {
282 dev_err(&pdev->dev, "invalid 'reg' property\n");
283 continue;
284 }
285
286 lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);
287 if (!lane) {
288 of_node_put(child);
289 return -ENOMEM;
290 }
291
292 phy = devm_phy_create(&pdev->dev, child,
293 &mvebu_a3700_comphy_ops);
294 if (IS_ERR(phy)) {
295 of_node_put(child);
296 return PTR_ERR(phy);
297 }
298
299 lane->dev = &pdev->dev;
300 lane->mode = PHY_MODE_INVALID;
301 lane->submode = PHY_INTERFACE_MODE_NA;
302 lane->id = lane_id;
303 lane->port = -1;
304 phy_set_drvdata(phy, lane);
305 }
306
307 provider = devm_of_phy_provider_register(&pdev->dev,
308 mvebu_a3700_comphy_xlate);
309 return PTR_ERR_OR_ZERO(provider);
310 }
311
312 static const struct of_device_id mvebu_a3700_comphy_of_match_table[] = {
313 { .compatible = "marvell,comphy-a3700" },
314 { },
315 };
316 MODULE_DEVICE_TABLE(of, mvebu_a3700_comphy_of_match_table);
317
318 static struct platform_driver mvebu_a3700_comphy_driver = {
319 .probe = mvebu_a3700_comphy_probe,
320 .driver = {
321 .name = "mvebu-a3700-comphy",
322 .of_match_table = mvebu_a3700_comphy_of_match_table,
323 },
324 };
325 module_platform_driver(mvebu_a3700_comphy_driver);
326
327 MODULE_AUTHOR("Miquèl Raynal <miquel.raynal@bootlin.com>");
328 MODULE_DESCRIPTION("Common PHY driver for A3700");
329 MODULE_LICENSE("GPL v2");