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

ibm_newemac: PowerPC 440EP/440GR EMAC PHY clock workaround

This patch adds ibm_newemac PHY clock workaround for 440EP/440GR EMAC
attached to a PHY which doesn't generate RX clock if there is no link.
The code is based on the previous ibm_emac driver stuff. The 440EP/440GR
allows controlling each EMAC clock separately as opposed to global clock
selection for 440GX.

BenH: Made that #ifdef CONFIG_PPC_DCR_NATIVE for now as dcri_* stuff doesn't
exist for MMIO type DCRs like Cell. Some future rework & improvements of the
DCR infrastructure will make that cleaner but for now, this makes it work.

Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by

Valentine Barshak and committed by
Jeff Garzik
11121e30 0925ab5d

+47 -2
+42 -1
drivers/net/ibm_newemac/core.c
··· 129 129 static inline void emac_report_timeout_error(struct emac_instance *dev, 130 130 const char *error) 131 131 { 132 - if (net_ratelimit()) 132 + if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | 133 + EMAC_FTR_440EP_PHY_CLK_FIX)) 134 + DBG(dev, "%s" NL, error); 135 + else if (net_ratelimit()) 133 136 printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); 137 + } 138 + 139 + /* EMAC PHY clock workaround: 140 + * 440EP/440GR has more sane SDR0_MFR register implementation than 440GX, 141 + * which allows controlling each EMAC clock 142 + */ 143 + static inline void emac_rx_clk_tx(struct emac_instance *dev) 144 + { 145 + #ifdef CONFIG_PPC_DCR_NATIVE 146 + if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX)) 147 + dcri_clrset(SDR0, SDR0_MFR, 148 + 0, SDR0_MFR_ECS >> dev->cell_index); 149 + #endif 150 + } 151 + 152 + static inline void emac_rx_clk_default(struct emac_instance *dev) 153 + { 154 + #ifdef CONFIG_PPC_DCR_NATIVE 155 + if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX)) 156 + dcri_clrset(SDR0, SDR0_MFR, 157 + SDR0_MFR_ECS >> dev->cell_index, 0); 158 + #endif 134 159 } 135 160 136 161 /* PHY polling intervals */ ··· 1124 1099 int link_poll_interval; 1125 1100 if (dev->phy.def->ops->poll_link(&dev->phy)) { 1126 1101 dev->phy.def->ops->read_link(&dev->phy); 1102 + emac_rx_clk_default(dev); 1127 1103 netif_carrier_on(dev->ndev); 1128 1104 link_poll_interval = PHY_POLL_LINK_ON; 1129 1105 } else { 1106 + emac_rx_clk_tx(dev); 1130 1107 netif_carrier_off(dev->ndev); 1131 1108 link_poll_interval = PHY_POLL_LINK_OFF; 1132 1109 } ··· 1206 1179 1207 1180 if (dev->phy.def->ops->poll_link(&dev->phy)) { 1208 1181 if (!netif_carrier_ok(dev->ndev)) { 1182 + emac_rx_clk_default(dev); 1209 1183 /* Get new link parameters */ 1210 1184 dev->phy.def->ops->read_link(&dev->phy); 1211 1185 ··· 1219 1191 link_poll_interval = PHY_POLL_LINK_ON; 1220 1192 } else { 1221 1193 if (netif_carrier_ok(dev->ndev)) { 1194 + emac_rx_clk_tx(dev); 1222 1195 netif_carrier_off(dev->ndev); 1223 1196 netif_tx_disable(dev->ndev); 1224 1197 emac_reinitialize(dev); ··· 2369 2340 if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) 2370 2341 dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); 2371 2342 #endif 2343 + /* PHY clock workaround */ 2344 + emac_rx_clk_tx(dev); 2345 + 2346 + /* Enable internal clock source on 440GX*/ 2347 + #ifdef CONFIG_PPC_DCR_NATIVE 2348 + if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) 2349 + dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); 2350 + #endif 2372 2351 /* Configure EMAC with defaults so we can at least use MDIO 2373 2352 * This is needed mostly for 440GX 2374 2353 */ ··· 2544 2507 dev->features |= EMAC_FTR_EMAC4; 2545 2508 if (of_device_is_compatible(np, "ibm,emac-440gx")) 2546 2509 dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX; 2510 + } else { 2511 + if (of_device_is_compatible(np, "ibm,emac-440ep") || 2512 + of_device_is_compatible(np, "ibm,emac-440gr")) 2513 + dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; 2547 2514 } 2548 2515 2549 2516 /* Fixup some feature bits based on the device tree */
+5 -1
drivers/net/ibm_newemac/core.h
··· 305 305 * Set if we need phy clock workaround for 440gx 306 306 */ 307 307 #define EMAC_FTR_440GX_PHY_CLK_FIX 0x00000080 308 + /* 309 + * Set if we need phy clock workaround for 440ep or 440gr 310 + */ 311 + #define EMAC_FTR_440EP_PHY_CLK_FIX 0x00000100 308 312 309 313 310 314 /* Right now, we don't quite handle the always/possible masks on the ··· 332 328 #ifdef CONFIG_IBM_NEW_EMAC_RGMII 333 329 EMAC_FTR_HAS_RGMII | 334 330 #endif 335 - 0, 331 + EMAC_FTR_440EP_PHY_CLK_FIX, 336 332 }; 337 333 338 334 static inline int emac_has_feature(struct emac_instance *dev,