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

net: phy: realtek: add support for configuring the RX delay on RTL8211F

On RTL8211F the RX and TX delays (2ns) can be configured in two ways:
- pin strapping (RXD1 for the TX delay and RXD0 for the RX delay, LOW
means "off" and HIGH means "on") which is read during PHY reset
- using software to configure the TX and RX delay registers

So far only the configuration using pin strapping has been supported.
Add support for enabling or disabling the RGMII RX delay based on the
phy-mode to be able to get the RX delay into a known state. This is
important because the RX delay has to be coordinated between the PHY,
MAC and the PCB design (trace length). With an invalid RX delay applied
(for example if both PHY and MAC add a 2ns RX delay) Ethernet may not
work at all.

Also add debug logging when configuring the RX delay (just like the TX
delay) because this is a common source of problems.

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Martin Blumenstingl and committed by
David S. Miller
1b3047b5 3aec743d

+36 -10
+36 -10
drivers/net/phy/realtek.c
··· 29 29 #define RTL8211F_INSR 0x1d 30 30 31 31 #define RTL8211F_TX_DELAY BIT(8) 32 + #define RTL8211F_RX_DELAY BIT(3) 33 + 32 34 #define RTL8211E_TX_DELAY BIT(1) 33 35 #define RTL8211E_RX_DELAY BIT(2) 34 36 #define RTL8211E_MODE_MII_GMII BIT(3) ··· 174 172 static int rtl8211f_config_init(struct phy_device *phydev) 175 173 { 176 174 struct device *dev = &phydev->mdio.dev; 177 - u16 val; 175 + u16 val_txdly, val_rxdly; 178 176 int ret; 179 177 180 - /* enable TX-delay for rgmii-{id,txid}, and disable it for rgmii and 181 - * rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin. 182 - */ 183 178 switch (phydev->interface) { 184 179 case PHY_INTERFACE_MODE_RGMII: 180 + val_txdly = 0; 181 + val_rxdly = 0; 182 + break; 183 + 185 184 case PHY_INTERFACE_MODE_RGMII_RXID: 186 - val = 0; 185 + val_txdly = 0; 186 + val_rxdly = RTL8211F_RX_DELAY; 187 187 break; 188 - case PHY_INTERFACE_MODE_RGMII_ID: 188 + 189 189 case PHY_INTERFACE_MODE_RGMII_TXID: 190 - val = RTL8211F_TX_DELAY; 190 + val_txdly = RTL8211F_TX_DELAY; 191 + val_rxdly = 0; 191 192 break; 193 + 194 + case PHY_INTERFACE_MODE_RGMII_ID: 195 + val_txdly = RTL8211F_TX_DELAY; 196 + val_rxdly = RTL8211F_RX_DELAY; 197 + break; 198 + 192 199 default: /* the rest of the modes imply leaving delay as is. */ 193 200 return 0; 194 201 } 195 202 196 203 ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, 197 - val); 204 + val_txdly); 198 205 if (ret < 0) { 199 206 dev_err(dev, "Failed to update the TX delay register\n"); 200 207 return ret; 201 208 } else if (ret) { 202 209 dev_dbg(dev, 203 210 "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", 204 - val ? "Enabling" : "Disabling"); 211 + val_txdly ? "Enabling" : "Disabling"); 205 212 } else { 206 213 dev_dbg(dev, 207 214 "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", 208 - val ? "enabled" : "disabled"); 215 + val_txdly ? "enabled" : "disabled"); 216 + } 217 + 218 + ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, 219 + val_rxdly); 220 + if (ret < 0) { 221 + dev_err(dev, "Failed to update the RX delay register\n"); 222 + return ret; 223 + } else if (ret) { 224 + dev_dbg(dev, 225 + "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", 226 + val_rxdly ? "Enabling" : "Disabling"); 227 + } else { 228 + dev_dbg(dev, 229 + "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", 230 + val_rxdly ? "enabled" : "disabled"); 209 231 } 210 232 211 233 return 0;