Skip to content

Commit bcf3440

Browse files
oleremdavem330
authored andcommitted
net: phy: micrel: add phy-mode support for the KSZ9031 PHY
Add support for following phy-modes: rgmii, rgmii-id, rgmii-txid, rgmii-rxid. This PHY has an internal RX delay of 1.2ns and no delay for TX. The pad skew registers allow to set the total TX delay to max 1.38ns and the total RX delay to max of 2.58ns (configurable 1.38ns + build in 1.2ns) and a minimal delay of 0ns. According to the RGMII v1.3 specification the delay provided by PCB traces should be between 1.5ns and 2.0ns. The RGMII v2.0 allows to provide this delay by MAC or PHY. So, we configure this PHY to the best values we can get by this HW: TX delay to 1.38ns (max supported value) and RX delay to 1.80ns (best calculated delay) The phy-modes can still be fine tuned/overwritten by *-skew-ps device tree properties described in: Documentation/devicetree/bindings/net/micrel-ksz90x1.txt Signed-off-by: Oleksij Rempel <[email protected]> Reviewed-by: Philippe Schenker <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8518307 commit bcf3440

File tree

1 file changed

+123
-5
lines changed

1 file changed

+123
-5
lines changed

drivers/net/phy/micrel.c

Lines changed: 123 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* ksz9477
2020
*/
2121

22+
#include <linux/bitfield.h>
2223
#include <linux/kernel.h>
2324
#include <linux/module.h>
2425
#include <linux/phy.h>
@@ -490,9 +491,50 @@ static int ksz9021_config_init(struct phy_device *phydev)
490491

491492
/* MMD Address 0x2 */
492493
#define MII_KSZ9031RN_CONTROL_PAD_SKEW 4
494+
#define MII_KSZ9031RN_RX_CTL_M GENMASK(7, 4)
495+
#define MII_KSZ9031RN_TX_CTL_M GENMASK(3, 0)
496+
493497
#define MII_KSZ9031RN_RX_DATA_PAD_SKEW 5
498+
#define MII_KSZ9031RN_RXD3 GENMASK(15, 12)
499+
#define MII_KSZ9031RN_RXD2 GENMASK(11, 8)
500+
#define MII_KSZ9031RN_RXD1 GENMASK(7, 4)
501+
#define MII_KSZ9031RN_RXD0 GENMASK(3, 0)
502+
494503
#define MII_KSZ9031RN_TX_DATA_PAD_SKEW 6
504+
#define MII_KSZ9031RN_TXD3 GENMASK(15, 12)
505+
#define MII_KSZ9031RN_TXD2 GENMASK(11, 8)
506+
#define MII_KSZ9031RN_TXD1 GENMASK(7, 4)
507+
#define MII_KSZ9031RN_TXD0 GENMASK(3, 0)
508+
495509
#define MII_KSZ9031RN_CLK_PAD_SKEW 8
510+
#define MII_KSZ9031RN_GTX_CLK GENMASK(9, 5)
511+
#define MII_KSZ9031RN_RX_CLK GENMASK(4, 0)
512+
513+
/* KSZ9031 has internal RGMII_IDRX = 1.2ns and RGMII_IDTX = 0ns. To
514+
* provide different RGMII options we need to configure delay offset
515+
* for each pad relative to build in delay.
516+
*/
517+
/* keep rx as "No delay adjustment" and set rx_clk to +0.60ns to get delays of
518+
* 1.80ns
519+
*/
520+
#define RX_ID 0x7
521+
#define RX_CLK_ID 0x19
522+
523+
/* set rx to +0.30ns and rx_clk to -0.90ns to compensate the
524+
* internal 1.2ns delay.
525+
*/
526+
#define RX_ND 0xc
527+
#define RX_CLK_ND 0x0
528+
529+
/* set tx to -0.42ns and tx_clk to +0.96ns to get 1.38ns delay */
530+
#define TX_ID 0x0
531+
#define TX_CLK_ID 0x1f
532+
533+
/* set tx and tx_clk to "No delay adjustment" to keep 0ns
534+
* dealy
535+
*/
536+
#define TX_ND 0x7
537+
#define TX_CLK_ND 0xf
496538

497539
/* MMD Address 0x1C */
498540
#define MII_KSZ9031RN_EDPD 0x23
@@ -501,7 +543,8 @@ static int ksz9021_config_init(struct phy_device *phydev)
501543
static int ksz9031_of_load_skew_values(struct phy_device *phydev,
502544
const struct device_node *of_node,
503545
u16 reg, size_t field_sz,
504-
const char *field[], u8 numfields)
546+
const char *field[], u8 numfields,
547+
bool *update)
505548
{
506549
int val[4] = {-1, -2, -3, -4};
507550
int matches = 0;
@@ -517,6 +560,8 @@ static int ksz9031_of_load_skew_values(struct phy_device *phydev,
517560
if (!matches)
518561
return 0;
519562

563+
*update |= true;
564+
520565
if (matches < numfields)
521566
newval = phy_read_mmd(phydev, 2, reg);
522567
else
@@ -565,6 +610,67 @@ static int ksz9031_enable_edpd(struct phy_device *phydev)
565610
reg | MII_KSZ9031RN_EDPD_ENABLE);
566611
}
567612

613+
static int ksz9031_config_rgmii_delay(struct phy_device *phydev)
614+
{
615+
u16 rx, tx, rx_clk, tx_clk;
616+
int ret;
617+
618+
switch (phydev->interface) {
619+
case PHY_INTERFACE_MODE_RGMII:
620+
tx = TX_ND;
621+
tx_clk = TX_CLK_ND;
622+
rx = RX_ND;
623+
rx_clk = RX_CLK_ND;
624+
break;
625+
case PHY_INTERFACE_MODE_RGMII_ID:
626+
tx = TX_ID;
627+
tx_clk = TX_CLK_ID;
628+
rx = RX_ID;
629+
rx_clk = RX_CLK_ID;
630+
break;
631+
case PHY_INTERFACE_MODE_RGMII_RXID:
632+
tx = TX_ND;
633+
tx_clk = TX_CLK_ND;
634+
rx = RX_ID;
635+
rx_clk = RX_CLK_ID;
636+
break;
637+
case PHY_INTERFACE_MODE_RGMII_TXID:
638+
tx = TX_ID;
639+
tx_clk = TX_CLK_ID;
640+
rx = RX_ND;
641+
rx_clk = RX_CLK_ND;
642+
break;
643+
default:
644+
return 0;
645+
}
646+
647+
ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_CONTROL_PAD_SKEW,
648+
FIELD_PREP(MII_KSZ9031RN_RX_CTL_M, rx) |
649+
FIELD_PREP(MII_KSZ9031RN_TX_CTL_M, tx));
650+
if (ret < 0)
651+
return ret;
652+
653+
ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_RX_DATA_PAD_SKEW,
654+
FIELD_PREP(MII_KSZ9031RN_RXD3, rx) |
655+
FIELD_PREP(MII_KSZ9031RN_RXD2, rx) |
656+
FIELD_PREP(MII_KSZ9031RN_RXD1, rx) |
657+
FIELD_PREP(MII_KSZ9031RN_RXD0, rx));
658+
if (ret < 0)
659+
return ret;
660+
661+
ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_TX_DATA_PAD_SKEW,
662+
FIELD_PREP(MII_KSZ9031RN_TXD3, tx) |
663+
FIELD_PREP(MII_KSZ9031RN_TXD2, tx) |
664+
FIELD_PREP(MII_KSZ9031RN_TXD1, tx) |
665+
FIELD_PREP(MII_KSZ9031RN_TXD0, tx));
666+
if (ret < 0)
667+
return ret;
668+
669+
return phy_write_mmd(phydev, 2, MII_KSZ9031RN_CLK_PAD_SKEW,
670+
FIELD_PREP(MII_KSZ9031RN_GTX_CLK, tx_clk) |
671+
FIELD_PREP(MII_KSZ9031RN_RX_CLK, rx_clk));
672+
}
673+
568674
static int ksz9031_config_init(struct phy_device *phydev)
569675
{
570676
const struct device *dev = &phydev->mdio.dev;
@@ -597,21 +703,33 @@ static int ksz9031_config_init(struct phy_device *phydev)
597703
} while (!of_node && dev_walker);
598704

599705
if (of_node) {
706+
bool update = false;
707+
708+
if (phy_interface_is_rgmii(phydev)) {
709+
result = ksz9031_config_rgmii_delay(phydev);
710+
if (result < 0)
711+
return result;
712+
}
713+
600714
ksz9031_of_load_skew_values(phydev, of_node,
601715
MII_KSZ9031RN_CLK_PAD_SKEW, 5,
602-
clk_skews, 2);
716+
clk_skews, 2, &update);
603717

604718
ksz9031_of_load_skew_values(phydev, of_node,
605719
MII_KSZ9031RN_CONTROL_PAD_SKEW, 4,
606-
control_skews, 2);
720+
control_skews, 2, &update);
607721

608722
ksz9031_of_load_skew_values(phydev, of_node,
609723
MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4,
610-
rx_data_skews, 4);
724+
rx_data_skews, 4, &update);
611725

612726
ksz9031_of_load_skew_values(phydev, of_node,
613727
MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
614-
tx_data_skews, 4);
728+
tx_data_skews, 4, &update);
729+
730+
if (update && phydev->interface != PHY_INTERFACE_MODE_RGMII)
731+
phydev_warn(phydev,
732+
"*-skew-ps values should be used only with phy-mode = \"rgmii\"\n");
615733

616734
/* Silicon Errata Sheet (DS80000691D or DS80000692D):
617735
* When the device links in the 1000BASE-T slave mode only,

0 commit comments

Comments
 (0)