|
23 | 23 |
|
24 | 24 | #define RTL821x_INSR 0x13
|
25 | 25 |
|
| 26 | +#define RTL821x_EXT_PAGE_SELECT 0x1e |
26 | 27 | #define RTL821x_PAGE_SELECT 0x1f
|
27 | 28 |
|
28 | 29 | #define RTL8211F_INSR 0x1d
|
29 | 30 |
|
30 | 31 | #define RTL8211F_TX_DELAY BIT(8)
|
| 32 | +#define RTL8211E_TX_DELAY BIT(1) |
| 33 | +#define RTL8211E_RX_DELAY BIT(2) |
| 34 | +#define RTL8211E_MODE_MII_GMII BIT(3) |
31 | 35 |
|
32 | 36 | #define RTL8201F_ISR 0x1e
|
33 | 37 | #define RTL8201F_IER 0x13
|
@@ -167,6 +171,52 @@ static int rtl8211f_config_init(struct phy_device *phydev)
|
167 | 171 | return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val);
|
168 | 172 | }
|
169 | 173 |
|
| 174 | +static int rtl8211e_config_init(struct phy_device *phydev) |
| 175 | +{ |
| 176 | + int ret = 0, oldpage; |
| 177 | + u16 val; |
| 178 | + |
| 179 | + /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ |
| 180 | + switch (phydev->interface) { |
| 181 | + case PHY_INTERFACE_MODE_RGMII: |
| 182 | + val = 0; |
| 183 | + break; |
| 184 | + case PHY_INTERFACE_MODE_RGMII_ID: |
| 185 | + val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; |
| 186 | + break; |
| 187 | + case PHY_INTERFACE_MODE_RGMII_RXID: |
| 188 | + val = RTL8211E_RX_DELAY; |
| 189 | + break; |
| 190 | + case PHY_INTERFACE_MODE_RGMII_TXID: |
| 191 | + val = RTL8211E_TX_DELAY; |
| 192 | + break; |
| 193 | + default: /* the rest of the modes imply leaving delays as is. */ |
| 194 | + return 0; |
| 195 | + } |
| 196 | + |
| 197 | + /* According to a sample driver there is a 0x1c config register on the |
| 198 | + * 0xa4 extension page (0x7) layout. It can be used to disable/enable |
| 199 | + * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can |
| 200 | + * also be used to customize the whole configuration register: |
| 201 | + * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select, |
| 202 | + * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet |
| 203 | + * for details). |
| 204 | + */ |
| 205 | + oldpage = phy_select_page(phydev, 0x7); |
| 206 | + if (oldpage < 0) |
| 207 | + goto err_restore_page; |
| 208 | + |
| 209 | + ret = phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); |
| 210 | + if (ret) |
| 211 | + goto err_restore_page; |
| 212 | + |
| 213 | + ret = phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, |
| 214 | + val); |
| 215 | + |
| 216 | +err_restore_page: |
| 217 | + return phy_restore_page(phydev, oldpage, ret); |
| 218 | +} |
| 219 | + |
170 | 220 | static int rtl8211b_suspend(struct phy_device *phydev)
|
171 | 221 | {
|
172 | 222 | phy_write(phydev, MII_MMD_DATA, BIT(9));
|
@@ -239,6 +289,7 @@ static struct phy_driver realtek_drvs[] = {
|
239 | 289 | }, {
|
240 | 290 | PHY_ID_MATCH_EXACT(0x001cc915),
|
241 | 291 | .name = "RTL8211E Gigabit Ethernet",
|
| 292 | + .config_init = &rtl8211e_config_init, |
242 | 293 | .ack_interrupt = &rtl821x_ack_interrupt,
|
243 | 294 | .config_intr = &rtl8211e_config_intr,
|
244 | 295 | .suspend = genphy_suspend,
|
|
0 commit comments