]> Git Repo - linux.git/blob - drivers/net/phy/qcom/qca807x.c
Linux 6.14-rc3
[linux.git] / drivers / net / phy / qcom / qca807x.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2023 Sartura Ltd.
4  *
5  * Author: Robert Marko <[email protected]>
6  *         Christian Marangi <[email protected]>
7  *
8  * Qualcomm QCA8072 and QCA8075 PHY driver
9  */
10
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/phy.h>
14 #include <linux/bitfield.h>
15 #include <linux/gpio/driver.h>
16 #include <linux/sfp.h>
17
18 #include "qcom.h"
19
20 #define QCA807X_CHIP_CONFIGURATION                              0x1f
21 #define QCA807X_BT_BX_REG_SEL                                   BIT(15)
22 #define QCA807X_BT_BX_REG_SEL_FIBER                             0
23 #define QCA807X_BT_BX_REG_SEL_COPPER                            1
24 #define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK                GENMASK(3, 0)
25 #define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII            4
26 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER            3
27 #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER       0
28
29 #define QCA807X_MEDIA_SELECT_STATUS                             0x1a
30 #define QCA807X_MEDIA_DETECTED_COPPER                           BIT(5)
31 #define QCA807X_MEDIA_DETECTED_1000_BASE_X                      BIT(4)
32 #define QCA807X_MEDIA_DETECTED_100_BASE_FX                      BIT(3)
33
34 #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION                  0x807e
35 #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN               BIT(0)
36
37 #define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH     0x801a
38 #define QCA807X_CONTROL_DAC_MASK                                GENMASK(2, 0)
39 /* List of tweaks enabled by this bit:
40  * - With both FULL amplitude and FULL bias current: bias current
41  *   is set to half.
42  * - With only DSP amplitude: bias current is set to half and
43  *   is set to 1/4 with cable < 10m.
44  * - With DSP bias current (included both DSP amplitude and
45  *   DSP bias current): bias current is half the detected current
46  *   with cable < 10m.
47  */
48 #define QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK                  BIT(2)
49 #define QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT                    BIT(1)
50 #define QCA807X_CONTROL_DAC_DSP_AMPLITUDE                       BIT(0)
51
52 #define QCA807X_MMD7_LED_100N_1                         0x8074
53 #define QCA807X_MMD7_LED_100N_2                         0x8075
54 #define QCA807X_MMD7_LED_1000N_1                        0x8076
55 #define QCA807X_MMD7_LED_1000N_2                        0x8077
56
57 #define QCA807X_MMD7_LED_CTRL(x)                        (0x8074 + ((x) * 2))
58 #define QCA807X_MMD7_LED_FORCE_CTRL(x)                  (0x8075 + ((x) * 2))
59
60 /* LED hw control pattern for fiber port */
61 #define QCA807X_LED_FIBER_PATTERN_MASK                  GENMASK(11, 1)
62 #define QCA807X_LED_FIBER_TXACT_BLK_EN                  BIT(10)
63 #define QCA807X_LED_FIBER_RXACT_BLK_EN                  BIT(9)
64 #define QCA807X_LED_FIBER_FDX_ON_EN                     BIT(6)
65 #define QCA807X_LED_FIBER_HDX_ON_EN                     BIT(5)
66 #define QCA807X_LED_FIBER_1000BX_ON_EN                  BIT(2)
67 #define QCA807X_LED_FIBER_100FX_ON_EN                   BIT(1)
68
69 /* Some device repurpose the LED as GPIO out */
70 #define QCA807X_GPIO_FORCE_EN                           QCA808X_LED_FORCE_EN
71 #define QCA807X_GPIO_FORCE_MODE_MASK                    QCA808X_LED_FORCE_MODE_MASK
72
73 #define QCA807X_FUNCTION_CONTROL                        0x10
74 #define QCA807X_FC_MDI_CROSSOVER_MODE_MASK              GENMASK(6, 5)
75 #define QCA807X_FC_MDI_CROSSOVER_AUTO                   3
76 #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX            1
77 #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI             0
78
79 /* PQSGMII Analog PHY specific */
80 #define PQSGMII_CTRL_REG                                0x0
81 #define PQSGMII_ANALOG_SW_RESET                         BIT(6)
82 #define PQSGMII_DRIVE_CONTROL_1                         0xb
83 #define PQSGMII_TX_DRIVER_MASK                          GENMASK(7, 4)
84 #define PQSGMII_TX_DRIVER_140MV                         0x0
85 #define PQSGMII_TX_DRIVER_160MV                         0x1
86 #define PQSGMII_TX_DRIVER_180MV                         0x2
87 #define PQSGMII_TX_DRIVER_200MV                         0x3
88 #define PQSGMII_TX_DRIVER_220MV                         0x4
89 #define PQSGMII_TX_DRIVER_240MV                         0x5
90 #define PQSGMII_TX_DRIVER_260MV                         0x6
91 #define PQSGMII_TX_DRIVER_280MV                         0x7
92 #define PQSGMII_TX_DRIVER_300MV                         0x8
93 #define PQSGMII_TX_DRIVER_320MV                         0x9
94 #define PQSGMII_TX_DRIVER_400MV                         0xa
95 #define PQSGMII_TX_DRIVER_500MV                         0xb
96 #define PQSGMII_TX_DRIVER_600MV                         0xc
97 #define PQSGMII_MODE_CTRL                               0x6d
98 #define PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK            BIT(0)
99 #define PQSGMII_MMD3_SERDES_CONTROL                     0x805a
100
101 #define PHY_ID_QCA8072          0x004dd0b2
102 #define PHY_ID_QCA8075          0x004dd0b1
103
104 #define QCA807X_COMBO_ADDR_OFFSET                       4
105 #define QCA807X_PQSGMII_ADDR_OFFSET                     5
106 #define SERDES_RESET_SLEEP                              100
107
108 enum qca807x_global_phy {
109         QCA807X_COMBO_ADDR = 4,
110         QCA807X_PQSGMII_ADDR = 5,
111 };
112
113 struct qca807x_shared_priv {
114         unsigned int package_mode;
115         u32 tx_drive_strength;
116 };
117
118 struct qca807x_gpio_priv {
119         struct phy_device *phy;
120 };
121
122 struct qca807x_priv {
123         bool dac_full_amplitude;
124         bool dac_full_bias_current;
125         bool dac_disable_bias_current_tweak;
126 };
127
128 static int qca807x_cable_test_start(struct phy_device *phydev)
129 {
130         /* we do all the (time consuming) work later */
131         return 0;
132 }
133
134 static int qca807x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
135                                     u16 *offload_trigger)
136 {
137         /* Parsing specific to netdev trigger */
138         switch (phydev->port) {
139         case PORT_TP:
140                 if (test_bit(TRIGGER_NETDEV_TX, &rules))
141                         *offload_trigger |= QCA808X_LED_TX_BLINK;
142                 if (test_bit(TRIGGER_NETDEV_RX, &rules))
143                         *offload_trigger |= QCA808X_LED_RX_BLINK;
144                 if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
145                         *offload_trigger |= QCA808X_LED_SPEED10_ON;
146                 if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
147                         *offload_trigger |= QCA808X_LED_SPEED100_ON;
148                 if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
149                         *offload_trigger |= QCA808X_LED_SPEED1000_ON;
150                 if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
151                         *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
152                 if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
153                         *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
154                 break;
155         case PORT_FIBRE:
156                 if (test_bit(TRIGGER_NETDEV_TX, &rules))
157                         *offload_trigger |= QCA807X_LED_FIBER_TXACT_BLK_EN;
158                 if (test_bit(TRIGGER_NETDEV_RX, &rules))
159                         *offload_trigger |= QCA807X_LED_FIBER_RXACT_BLK_EN;
160                 if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
161                         *offload_trigger |= QCA807X_LED_FIBER_100FX_ON_EN;
162                 if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
163                         *offload_trigger |= QCA807X_LED_FIBER_1000BX_ON_EN;
164                 if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
165                         *offload_trigger |= QCA807X_LED_FIBER_HDX_ON_EN;
166                 if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
167                         *offload_trigger |= QCA807X_LED_FIBER_FDX_ON_EN;
168                 break;
169         default:
170                 return -EOPNOTSUPP;
171         }
172
173         if (rules && !*offload_trigger)
174                 return -EOPNOTSUPP;
175
176         return 0;
177 }
178
179 static int qca807x_led_hw_control_enable(struct phy_device *phydev, u8 index)
180 {
181         u16 reg;
182
183         if (index > 1)
184                 return -EINVAL;
185
186         reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
187         return qca808x_led_reg_hw_control_enable(phydev, reg);
188 }
189
190 static int qca807x_led_hw_is_supported(struct phy_device *phydev, u8 index,
191                                        unsigned long rules)
192 {
193         u16 offload_trigger = 0;
194
195         if (index > 1)
196                 return -EINVAL;
197
198         return qca807x_led_parse_netdev(phydev, rules, &offload_trigger);
199 }
200
201 static int qca807x_led_hw_control_set(struct phy_device *phydev, u8 index,
202                                       unsigned long rules)
203 {
204         u16 reg, mask, offload_trigger = 0;
205         int ret;
206
207         if (index > 1)
208                 return -EINVAL;
209
210         ret = qca807x_led_parse_netdev(phydev, rules, &offload_trigger);
211         if (ret)
212                 return ret;
213
214         ret = qca807x_led_hw_control_enable(phydev, index);
215         if (ret)
216                 return ret;
217
218         switch (phydev->port) {
219         case PORT_TP:
220                 reg = QCA807X_MMD7_LED_CTRL(index);
221                 mask = QCA808X_LED_PATTERN_MASK;
222                 break;
223         case PORT_FIBRE:
224                 /* HW control pattern bits are in LED FORCE reg */
225                 reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
226                 mask = QCA807X_LED_FIBER_PATTERN_MASK;
227                 break;
228         default:
229                 return -EINVAL;
230         }
231
232         return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, mask,
233                               offload_trigger);
234 }
235
236 static bool qca807x_led_hw_control_status(struct phy_device *phydev, u8 index)
237 {
238         u16 reg;
239
240         if (index > 1)
241                 return false;
242
243         reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
244         return qca808x_led_reg_hw_control_status(phydev, reg);
245 }
246
247 static int qca807x_led_hw_control_get(struct phy_device *phydev, u8 index,
248                                       unsigned long *rules)
249 {
250         u16 reg;
251         int val;
252
253         if (index > 1)
254                 return -EINVAL;
255
256         /* Check if we have hw control enabled */
257         if (qca807x_led_hw_control_status(phydev, index))
258                 return -EINVAL;
259
260         /* Parsing specific to netdev trigger */
261         switch (phydev->port) {
262         case PORT_TP:
263                 reg = QCA807X_MMD7_LED_CTRL(index);
264                 val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
265                 if (val & QCA808X_LED_TX_BLINK)
266                         set_bit(TRIGGER_NETDEV_TX, rules);
267                 if (val & QCA808X_LED_RX_BLINK)
268                         set_bit(TRIGGER_NETDEV_RX, rules);
269                 if (val & QCA808X_LED_SPEED10_ON)
270                         set_bit(TRIGGER_NETDEV_LINK_10, rules);
271                 if (val & QCA808X_LED_SPEED100_ON)
272                         set_bit(TRIGGER_NETDEV_LINK_100, rules);
273                 if (val & QCA808X_LED_SPEED1000_ON)
274                         set_bit(TRIGGER_NETDEV_LINK_1000, rules);
275                 if (val & QCA808X_LED_HALF_DUPLEX_ON)
276                         set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
277                 if (val & QCA808X_LED_FULL_DUPLEX_ON)
278                         set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
279                 break;
280         case PORT_FIBRE:
281                 /* HW control pattern bits are in LED FORCE reg */
282                 reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
283                 val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
284                 if (val & QCA807X_LED_FIBER_TXACT_BLK_EN)
285                         set_bit(TRIGGER_NETDEV_TX, rules);
286                 if (val & QCA807X_LED_FIBER_RXACT_BLK_EN)
287                         set_bit(TRIGGER_NETDEV_RX, rules);
288                 if (val & QCA807X_LED_FIBER_100FX_ON_EN)
289                         set_bit(TRIGGER_NETDEV_LINK_100, rules);
290                 if (val & QCA807X_LED_FIBER_1000BX_ON_EN)
291                         set_bit(TRIGGER_NETDEV_LINK_1000, rules);
292                 if (val & QCA807X_LED_FIBER_HDX_ON_EN)
293                         set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
294                 if (val & QCA807X_LED_FIBER_FDX_ON_EN)
295                         set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
296                 break;
297         default:
298                 return -EINVAL;
299         }
300
301         return 0;
302 }
303
304 static int qca807x_led_hw_control_reset(struct phy_device *phydev, u8 index)
305 {
306         u16 reg, mask;
307
308         if (index > 1)
309                 return -EINVAL;
310
311         switch (phydev->port) {
312         case PORT_TP:
313                 reg = QCA807X_MMD7_LED_CTRL(index);
314                 mask = QCA808X_LED_PATTERN_MASK;
315                 break;
316         case PORT_FIBRE:
317                 /* HW control pattern bits are in LED FORCE reg */
318                 reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
319                 mask = QCA807X_LED_FIBER_PATTERN_MASK;
320                 break;
321         default:
322                 return -EINVAL;
323         }
324
325         return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, mask);
326 }
327
328 static int qca807x_led_brightness_set(struct phy_device *phydev,
329                                       u8 index, enum led_brightness value)
330 {
331         u16 reg;
332         int ret;
333
334         if (index > 1)
335                 return -EINVAL;
336
337         /* If we are setting off the LED reset any hw control rule */
338         if (!value) {
339                 ret = qca807x_led_hw_control_reset(phydev, index);
340                 if (ret)
341                         return ret;
342         }
343
344         reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
345         return qca808x_led_reg_brightness_set(phydev, reg, value);
346 }
347
348 static int qca807x_led_blink_set(struct phy_device *phydev, u8 index,
349                                  unsigned long *delay_on,
350                                  unsigned long *delay_off)
351 {
352         u16 reg;
353
354         if (index > 1)
355                 return -EINVAL;
356
357         reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
358         return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);
359 }
360
361 #ifdef CONFIG_GPIOLIB
362 static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
363 {
364         return GPIO_LINE_DIRECTION_OUT;
365 }
366
367 static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset)
368 {
369         struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
370         u16 reg;
371         int val;
372
373         reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
374         val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
375
376         return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
377 }
378
379 static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
380 {
381         struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
382         u16 reg;
383         int val;
384
385         reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
386
387         val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
388         val &= ~QCA807X_GPIO_FORCE_MODE_MASK;
389         val |= QCA807X_GPIO_FORCE_EN;
390         val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value);
391
392         phy_write_mmd(priv->phy, MDIO_MMD_AN, reg, val);
393 }
394
395 static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value)
396 {
397         qca807x_gpio_set(gc, offset, value);
398
399         return 0;
400 }
401
402 static int qca807x_gpio(struct phy_device *phydev)
403 {
404         struct device *dev = &phydev->mdio.dev;
405         struct qca807x_gpio_priv *priv;
406         struct gpio_chip *gc;
407
408         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
409         if (!priv)
410                 return -ENOMEM;
411
412         priv->phy = phydev;
413
414         gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
415         if (!gc)
416                 return -ENOMEM;
417
418         gc->label = dev_name(dev);
419         gc->base = -1;
420         gc->ngpio = 2;
421         gc->parent = dev;
422         gc->owner = THIS_MODULE;
423         gc->can_sleep = true;
424         gc->get_direction = qca807x_gpio_get_direction;
425         gc->direction_output = qca807x_gpio_dir_out;
426         gc->get = qca807x_gpio_get;
427         gc->set = qca807x_gpio_set;
428
429         return devm_gpiochip_add_data(dev, gc, priv);
430 }
431 #endif
432
433 static int qca807x_read_fiber_status(struct phy_device *phydev)
434 {
435         bool changed;
436         int ss, err;
437
438         err = genphy_c37_read_status(phydev, &changed);
439         if (err || !changed)
440                 return err;
441
442         /* Read the QCA807x PHY-Specific Status register fiber page,
443          * which indicates the speed and duplex that the PHY is actually
444          * using, irrespective of whether we are in autoneg mode or not.
445          */
446         ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
447         if (ss < 0)
448                 return ss;
449
450         phydev->speed = SPEED_UNKNOWN;
451         phydev->duplex = DUPLEX_UNKNOWN;
452         if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
453                 switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) {
454                 case AT803X_SS_SPEED_100:
455                         phydev->speed = SPEED_100;
456                         break;
457                 case AT803X_SS_SPEED_1000:
458                         phydev->speed = SPEED_1000;
459                         break;
460                 }
461
462                 if (ss & AT803X_SS_DUPLEX)
463                         phydev->duplex = DUPLEX_FULL;
464                 else
465                         phydev->duplex = DUPLEX_HALF;
466         }
467
468         return 0;
469 }
470
471 static int qca807x_read_status(struct phy_device *phydev)
472 {
473         if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
474                 switch (phydev->port) {
475                 case PORT_FIBRE:
476                         return qca807x_read_fiber_status(phydev);
477                 case PORT_TP:
478                         return at803x_read_status(phydev);
479                 default:
480                         return -EINVAL;
481                 }
482         }
483
484         return at803x_read_status(phydev);
485 }
486
487 static int qca807x_phy_package_probe_once(struct phy_device *phydev)
488 {
489         struct phy_package_shared *shared = phydev->shared;
490         struct qca807x_shared_priv *priv = shared->priv;
491         unsigned int tx_drive_strength;
492         const char *package_mode_name;
493
494         /* Default to 600mw if not defined */
495         if (of_property_read_u32(shared->np, "qcom,tx-drive-strength-milliwatt",
496                                  &tx_drive_strength))
497                 tx_drive_strength = 600;
498
499         switch (tx_drive_strength) {
500         case 140:
501                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_140MV;
502                 break;
503         case 160:
504                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_160MV;
505                 break;
506         case 180:
507                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_180MV;
508                 break;
509         case 200:
510                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_200MV;
511                 break;
512         case 220:
513                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_220MV;
514                 break;
515         case 240:
516                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_240MV;
517                 break;
518         case 260:
519                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_260MV;
520                 break;
521         case 280:
522                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_280MV;
523                 break;
524         case 300:
525                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_300MV;
526                 break;
527         case 320:
528                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_320MV;
529                 break;
530         case 400:
531                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_400MV;
532                 break;
533         case 500:
534                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_500MV;
535                 break;
536         case 600:
537                 priv->tx_drive_strength = PQSGMII_TX_DRIVER_600MV;
538                 break;
539         default:
540                 return -EINVAL;
541         }
542
543         priv->package_mode = PHY_INTERFACE_MODE_NA;
544         if (!of_property_read_string(shared->np, "qcom,package-mode",
545                                      &package_mode_name)) {
546                 if (!strcasecmp(package_mode_name,
547                                 phy_modes(PHY_INTERFACE_MODE_PSGMII)))
548                         priv->package_mode = PHY_INTERFACE_MODE_PSGMII;
549                 else if (!strcasecmp(package_mode_name,
550                                      phy_modes(PHY_INTERFACE_MODE_QSGMII)))
551                         priv->package_mode = PHY_INTERFACE_MODE_QSGMII;
552                 else
553                         return -EINVAL;
554         }
555
556         return 0;
557 }
558
559 static int qca807x_phy_package_config_init_once(struct phy_device *phydev)
560 {
561         struct phy_package_shared *shared = phydev->shared;
562         struct qca807x_shared_priv *priv = shared->priv;
563         int val, ret;
564
565         /* Make sure PHY follow PHY package mode if enforced */
566         if (priv->package_mode != PHY_INTERFACE_MODE_NA &&
567             phydev->interface != priv->package_mode)
568                 return -EINVAL;
569
570         phy_lock_mdio_bus(phydev);
571
572         /* Set correct PHY package mode */
573         val = __phy_package_read(phydev, QCA807X_COMBO_ADDR,
574                                  QCA807X_CHIP_CONFIGURATION);
575         val &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK;
576         /* package_mode can be QSGMII or PSGMII and we validate
577          * this in probe_once.
578          * With package_mode to NA, we default to PSGMII.
579          */
580         switch (priv->package_mode) {
581         case PHY_INTERFACE_MODE_QSGMII:
582                 val |= QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII;
583                 break;
584         case PHY_INTERFACE_MODE_PSGMII:
585         default:
586                 val |= QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER;
587         }
588         ret = __phy_package_write(phydev, QCA807X_COMBO_ADDR,
589                                   QCA807X_CHIP_CONFIGURATION, val);
590         if (ret)
591                 goto exit;
592
593         /* After mode change Serdes reset is required */
594         val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
595                                  PQSGMII_CTRL_REG);
596         val &= ~PQSGMII_ANALOG_SW_RESET;
597         ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
598                                   PQSGMII_CTRL_REG, val);
599         if (ret)
600                 goto exit;
601
602         msleep(SERDES_RESET_SLEEP);
603
604         val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
605                                  PQSGMII_CTRL_REG);
606         val |= PQSGMII_ANALOG_SW_RESET;
607         ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
608                                   PQSGMII_CTRL_REG, val);
609         if (ret)
610                 goto exit;
611
612         /* Workaround to enable AZ transmitting ability */
613         val = __phy_package_read_mmd(phydev, QCA807X_PQSGMII_ADDR,
614                                      MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL);
615         val &= ~PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK;
616         ret = __phy_package_write_mmd(phydev, QCA807X_PQSGMII_ADDR,
617                                       MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL, val);
618         if (ret)
619                 goto exit;
620
621         /* Set PQSGMII TX AMP strength */
622         val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
623                                  PQSGMII_DRIVE_CONTROL_1);
624         val &= ~PQSGMII_TX_DRIVER_MASK;
625         val |= FIELD_PREP(PQSGMII_TX_DRIVER_MASK, priv->tx_drive_strength);
626         ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
627                                   PQSGMII_DRIVE_CONTROL_1, val);
628         if (ret)
629                 goto exit;
630
631         /* Prevent PSGMII going into hibernation via PSGMII self test */
632         val = __phy_package_read_mmd(phydev, QCA807X_COMBO_ADDR,
633                                      MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL);
634         val &= ~BIT(1);
635         ret = __phy_package_write_mmd(phydev, QCA807X_COMBO_ADDR,
636                                       MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL, val);
637
638 exit:
639         phy_unlock_mdio_bus(phydev);
640
641         return ret;
642 }
643
644 static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
645 {
646         struct phy_device *phydev = upstream;
647         __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
648         phy_interface_t iface;
649         int ret;
650         DECLARE_PHY_INTERFACE_MASK(interfaces);
651
652         sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
653         iface = sfp_select_interface(phydev->sfp_bus, support);
654
655         dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface));
656
657         switch (iface) {
658         case PHY_INTERFACE_MODE_1000BASEX:
659         case PHY_INTERFACE_MODE_100BASEX:
660                 /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
661                 ret = phy_modify(phydev,
662                                  QCA807X_CHIP_CONFIGURATION,
663                                  QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
664                                  QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
665                 /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
666                 ret = phy_set_bits_mmd(phydev,
667                                        MDIO_MMD_AN,
668                                        QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
669                                        QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN);
670                 /* Select fiber page */
671                 ret = phy_clear_bits(phydev,
672                                      QCA807X_CHIP_CONFIGURATION,
673                                      QCA807X_BT_BX_REG_SEL);
674
675                 phydev->port = PORT_FIBRE;
676                 break;
677         default:
678                 dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n");
679                 return -EINVAL;
680         }
681
682         return ret;
683 }
684
685 static void qca807x_sfp_remove(void *upstream)
686 {
687         struct phy_device *phydev = upstream;
688
689         /* Select copper page */
690         phy_set_bits(phydev,
691                      QCA807X_CHIP_CONFIGURATION,
692                      QCA807X_BT_BX_REG_SEL);
693
694         phydev->port = PORT_TP;
695 }
696
697 static const struct sfp_upstream_ops qca807x_sfp_ops = {
698         .attach = phy_sfp_attach,
699         .detach = phy_sfp_detach,
700         .module_insert = qca807x_sfp_insert,
701         .module_remove = qca807x_sfp_remove,
702         .connect_phy = phy_sfp_connect_phy,
703         .disconnect_phy = phy_sfp_disconnect_phy,
704 };
705
706 static int qca807x_probe(struct phy_device *phydev)
707 {
708         struct device_node *node = phydev->mdio.dev.of_node;
709         struct qca807x_shared_priv *shared_priv;
710         struct device *dev = &phydev->mdio.dev;
711         struct phy_package_shared *shared;
712         struct qca807x_priv *priv;
713         int ret;
714
715         ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));
716         if (ret)
717                 return ret;
718
719         if (phy_package_probe_once(phydev)) {
720                 ret = qca807x_phy_package_probe_once(phydev);
721                 if (ret)
722                         return ret;
723         }
724
725         shared = phydev->shared;
726         shared_priv = shared->priv;
727
728         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
729         if (!priv)
730                 return -ENOMEM;
731
732         priv->dac_full_amplitude = of_property_read_bool(node, "qcom,dac-full-amplitude");
733         priv->dac_full_bias_current = of_property_read_bool(node, "qcom,dac-full-bias-current");
734         priv->dac_disable_bias_current_tweak = of_property_read_bool(node,
735                                                                      "qcom,dac-disable-bias-current-tweak");
736
737 #if IS_ENABLED(CONFIG_GPIOLIB)
738         /* Do not register a GPIO controller unless flagged for it */
739         if (of_property_read_bool(node, "gpio-controller")) {
740                 ret = qca807x_gpio(phydev);
741                 if (ret)
742                         return ret;
743         }
744 #endif
745
746         /* Attach SFP bus on combo port*/
747         if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
748                 ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
749                 if (ret)
750                         return ret;
751                 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
752                 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
753         }
754
755         phydev->priv = priv;
756
757         return 0;
758 }
759
760 static int qca807x_config_init(struct phy_device *phydev)
761 {
762         struct qca807x_priv *priv = phydev->priv;
763         u16 control_dac;
764         int ret;
765
766         if (phy_package_init_once(phydev)) {
767                 ret = qca807x_phy_package_config_init_once(phydev);
768                 if (ret)
769                         return ret;
770         }
771
772         control_dac = phy_read_mmd(phydev, MDIO_MMD_AN,
773                                    QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH);
774         control_dac &= ~QCA807X_CONTROL_DAC_MASK;
775         if (!priv->dac_full_amplitude)
776                 control_dac |= QCA807X_CONTROL_DAC_DSP_AMPLITUDE;
777         if (!priv->dac_full_amplitude)
778                 control_dac |= QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT;
779         if (!priv->dac_disable_bias_current_tweak)
780                 control_dac |= QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK;
781         return phy_write_mmd(phydev, MDIO_MMD_AN,
782                              QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH,
783                              control_dac);
784 }
785
786 static struct phy_driver qca807x_drivers[] = {
787         {
788                 PHY_ID_MATCH_EXACT(PHY_ID_QCA8072),
789                 .name           = "Qualcomm QCA8072",
790                 .flags          = PHY_POLL_CABLE_TEST,
791                 /* PHY_GBIT_FEATURES */
792                 .probe          = qca807x_probe,
793                 .config_init    = qca807x_config_init,
794                 .read_status    = qca807x_read_status,
795                 .config_intr    = at803x_config_intr,
796                 .handle_interrupt = at803x_handle_interrupt,
797                 .soft_reset     = genphy_soft_reset,
798                 .get_tunable    = at803x_get_tunable,
799                 .set_tunable    = at803x_set_tunable,
800                 .resume         = genphy_resume,
801                 .suspend        = genphy_suspend,
802                 .cable_test_start       = qca807x_cable_test_start,
803                 .cable_test_get_status  = qca808x_cable_test_get_status,
804         },
805         {
806                 PHY_ID_MATCH_EXACT(PHY_ID_QCA8075),
807                 .name           = "Qualcomm QCA8075",
808                 .flags          = PHY_POLL_CABLE_TEST,
809                 /* PHY_GBIT_FEATURES */
810                 .probe          = qca807x_probe,
811                 .config_init    = qca807x_config_init,
812                 .read_status    = qca807x_read_status,
813                 .config_intr    = at803x_config_intr,
814                 .handle_interrupt = at803x_handle_interrupt,
815                 .soft_reset     = genphy_soft_reset,
816                 .get_tunable    = at803x_get_tunable,
817                 .set_tunable    = at803x_set_tunable,
818                 .resume         = genphy_resume,
819                 .suspend        = genphy_suspend,
820                 .cable_test_start       = qca807x_cable_test_start,
821                 .cable_test_get_status  = qca808x_cable_test_get_status,
822                 .led_brightness_set = qca807x_led_brightness_set,
823                 .led_blink_set = qca807x_led_blink_set,
824                 .led_hw_is_supported = qca807x_led_hw_is_supported,
825                 .led_hw_control_set = qca807x_led_hw_control_set,
826                 .led_hw_control_get = qca807x_led_hw_control_get,
827         },
828 };
829 module_phy_driver(qca807x_drivers);
830
831 static const struct mdio_device_id __maybe_unused qca807x_tbl[] = {
832         { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
833         { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
834         { }
835 };
836
837 MODULE_AUTHOR("Robert Marko <[email protected]>");
838 MODULE_AUTHOR("Christian Marangi <[email protected]>");
839 MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver");
840 MODULE_DEVICE_TABLE(mdio, qca807x_tbl);
841 MODULE_LICENSE("GPL");
This page took 0.077533 seconds and 4 git commands to generate.