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