Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: intel-xway: Add RGMII internal delay configuration

This adds the possibility to configure the RGMII RX/TX clock skew via
devicetree.

Simply set phy mode to "rgmii-id", "rgmii-rxid" or "rgmii-txid" and add
the "rx-internal-delay-ps" or "tx-internal-delay-ps" property to the
devicetree.

Furthermore, a warning is now issued if the phy mode is configured to
"rgmii" and an internal delay is set in the phy (e.g. by pin-strapping),
as in the dp83867 driver.

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Martin Schiller and committed by
David S. Miller
be393dd6 d34869b4

+76
+76
drivers/net/phy/intel-xway.c
··· 8 8 #include <linux/module.h> 9 9 #include <linux/phy.h> 10 10 #include <linux/of.h> 11 + #include <linux/bitfield.h> 11 12 13 + #define XWAY_MDIO_MIICTRL 0x17 /* mii control */ 12 14 #define XWAY_MDIO_IMASK 0x19 /* interrupt mask */ 13 15 #define XWAY_MDIO_ISTAT 0x1A /* interrupt status */ 14 16 #define XWAY_MDIO_LED 0x1B /* led control */ 17 + 18 + #define XWAY_MDIO_MIICTRL_RXSKEW_MASK GENMASK(14, 12) 19 + #define XWAY_MDIO_MIICTRL_TXSKEW_MASK GENMASK(10, 8) 15 20 16 21 /* bit 15:12 are reserved */ 17 22 #define XWAY_MDIO_LED_LED3_EN BIT(11) /* Enable the integrated function of LED3 */ ··· 162 157 #define PHY_ID_PHY11G_VR9_1_2 0xD565A409 163 158 #define PHY_ID_PHY22F_VR9_1_2 0xD565A419 164 159 160 + static const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500, 161 + 3000, 3500}; 162 + 163 + static int xway_gphy_rgmii_init(struct phy_device *phydev) 164 + { 165 + struct device *dev = &phydev->mdio.dev; 166 + unsigned int delay_size = ARRAY_SIZE(xway_internal_delay); 167 + s32 int_delay; 168 + int val = 0; 169 + 170 + if (!phy_interface_is_rgmii(phydev)) 171 + return 0; 172 + 173 + /* Existing behavior was to use default pin strapping delay in rgmii 174 + * mode, but rgmii should have meant no delay. Warn existing users, 175 + * but do not change anything at the moment. 176 + */ 177 + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { 178 + u16 txskew, rxskew; 179 + 180 + val = phy_read(phydev, XWAY_MDIO_MIICTRL); 181 + if (val < 0) 182 + return val; 183 + 184 + txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 185 + rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val); 186 + 187 + if (txskew > 0 || rxskew > 0) 188 + phydev_warn(phydev, 189 + "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n" 190 + "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n", 191 + xway_internal_delay[txskew], 192 + xway_internal_delay[rxskew]); 193 + return 0; 194 + } 195 + 196 + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 197 + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 198 + int_delay = phy_get_internal_delay(phydev, dev, 199 + xway_internal_delay, 200 + delay_size, true); 201 + 202 + /* if rx-internal-delay-ps is missing, use default of 2.0 ns */ 203 + if (int_delay < 0) 204 + int_delay = 4; /* 2000 ps */ 205 + 206 + val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay); 207 + } 208 + 209 + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 210 + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 211 + int_delay = phy_get_internal_delay(phydev, dev, 212 + xway_internal_delay, 213 + delay_size, false); 214 + 215 + /* if tx-internal-delay-ps is missing, use default of 2.0 ns */ 216 + if (int_delay < 0) 217 + int_delay = 4; /* 2000 ps */ 218 + 219 + val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay); 220 + } 221 + 222 + return phy_modify(phydev, XWAY_MDIO_MIICTRL, 223 + XWAY_MDIO_MIICTRL_RXSKEW_MASK | 224 + XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); 225 + } 226 + 165 227 static int xway_gphy_config_init(struct phy_device *phydev) 166 228 { 167 229 int err; ··· 275 203 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl); 276 204 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); 277 205 phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); 206 + 207 + err = xway_gphy_rgmii_init(phydev); 208 + if (err) 209 + return err; 278 210 279 211 return 0; 280 212 }