diff options
author | Valentine Barshak <vbarshak@ru.mvista.com> | 2008-04-21 20:46:48 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-04-25 02:08:08 -0400 |
commit | 11121e3008a9282fc185cb2e81eda2d5436d099b (patch) | |
tree | 76bdf974ea16692f90c4cea5ab87c3aee81d8ef0 /drivers/net/ibm_newemac | |
parent | 0925ab5d385b6cd1c435c82bfc01898c81f3d062 (diff) |
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>
Diffstat (limited to 'drivers/net/ibm_newemac')
-rw-r--r-- | drivers/net/ibm_newemac/core.c | 43 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/core.h | 6 |
2 files changed, 47 insertions, 2 deletions
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 4176dd6a2e83..490d690b5e7f 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c | |||
@@ -129,10 +129,35 @@ static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE]; | |||
129 | static inline void emac_report_timeout_error(struct emac_instance *dev, | 129 | static inline void emac_report_timeout_error(struct emac_instance *dev, |
130 | const char *error) | 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 | printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); | 136 | printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); |
134 | } | 137 | } |
135 | 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 | ||
159 | } | ||
160 | |||
136 | /* PHY polling intervals */ | 161 | /* PHY polling intervals */ |
137 | #define PHY_POLL_LINK_ON HZ | 162 | #define PHY_POLL_LINK_ON HZ |
138 | #define PHY_POLL_LINK_OFF (HZ / 5) | 163 | #define PHY_POLL_LINK_OFF (HZ / 5) |
@@ -1099,9 +1124,11 @@ static int emac_open(struct net_device *ndev) | |||
1099 | int link_poll_interval; | 1124 | int link_poll_interval; |
1100 | if (dev->phy.def->ops->poll_link(&dev->phy)) { | 1125 | if (dev->phy.def->ops->poll_link(&dev->phy)) { |
1101 | dev->phy.def->ops->read_link(&dev->phy); | 1126 | dev->phy.def->ops->read_link(&dev->phy); |
1127 | emac_rx_clk_default(dev); | ||
1102 | netif_carrier_on(dev->ndev); | 1128 | netif_carrier_on(dev->ndev); |
1103 | link_poll_interval = PHY_POLL_LINK_ON; | 1129 | link_poll_interval = PHY_POLL_LINK_ON; |
1104 | } else { | 1130 | } else { |
1131 | emac_rx_clk_tx(dev); | ||
1105 | netif_carrier_off(dev->ndev); | 1132 | netif_carrier_off(dev->ndev); |
1106 | link_poll_interval = PHY_POLL_LINK_OFF; | 1133 | link_poll_interval = PHY_POLL_LINK_OFF; |
1107 | } | 1134 | } |
@@ -1179,6 +1206,7 @@ static void emac_link_timer(struct work_struct *work) | |||
1179 | 1206 | ||
1180 | if (dev->phy.def->ops->poll_link(&dev->phy)) { | 1207 | if (dev->phy.def->ops->poll_link(&dev->phy)) { |
1181 | if (!netif_carrier_ok(dev->ndev)) { | 1208 | if (!netif_carrier_ok(dev->ndev)) { |
1209 | emac_rx_clk_default(dev); | ||
1182 | /* Get new link parameters */ | 1210 | /* Get new link parameters */ |
1183 | dev->phy.def->ops->read_link(&dev->phy); | 1211 | dev->phy.def->ops->read_link(&dev->phy); |
1184 | 1212 | ||
@@ -1191,6 +1219,7 @@ static void emac_link_timer(struct work_struct *work) | |||
1191 | link_poll_interval = PHY_POLL_LINK_ON; | 1219 | link_poll_interval = PHY_POLL_LINK_ON; |
1192 | } else { | 1220 | } else { |
1193 | if (netif_carrier_ok(dev->ndev)) { | 1221 | if (netif_carrier_ok(dev->ndev)) { |
1222 | emac_rx_clk_tx(dev); | ||
1194 | netif_carrier_off(dev->ndev); | 1223 | netif_carrier_off(dev->ndev); |
1195 | netif_tx_disable(dev->ndev); | 1224 | netif_tx_disable(dev->ndev); |
1196 | emac_reinitialize(dev); | 1225 | emac_reinitialize(dev); |
@@ -2340,6 +2369,14 @@ static int __devinit emac_init_phy(struct emac_instance *dev) | |||
2340 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) | 2369 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) |
2341 | dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); | 2370 | dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); |
2342 | #endif | 2371 | #endif |
2372 | /* PHY clock workaround */ | ||
2373 | emac_rx_clk_tx(dev); | ||
2374 | |||
2375 | /* Enable internal clock source on 440GX*/ | ||
2376 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
2377 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) | ||
2378 | dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); | ||
2379 | #endif | ||
2343 | /* Configure EMAC with defaults so we can at least use MDIO | 2380 | /* Configure EMAC with defaults so we can at least use MDIO |
2344 | * This is needed mostly for 440GX | 2381 | * This is needed mostly for 440GX |
2345 | */ | 2382 | */ |
@@ -2507,6 +2544,10 @@ static int __devinit emac_init_config(struct emac_instance *dev) | |||
2507 | dev->features |= EMAC_FTR_EMAC4; | 2544 | dev->features |= EMAC_FTR_EMAC4; |
2508 | if (of_device_is_compatible(np, "ibm,emac-440gx")) | 2545 | if (of_device_is_compatible(np, "ibm,emac-440gx")) |
2509 | dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX; | 2546 | dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX; |
2547 | } else { | ||
2548 | if (of_device_is_compatible(np, "ibm,emac-440ep") || | ||
2549 | of_device_is_compatible(np, "ibm,emac-440gr")) | ||
2550 | dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; | ||
2510 | } | 2551 | } |
2511 | 2552 | ||
2512 | /* Fixup some feature bits based on the device tree */ | 2553 | /* Fixup some feature bits based on the device tree */ |
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 96ec48266b4a..1683db9870a4 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h | |||
@@ -305,6 +305,10 @@ struct emac_instance { | |||
305 | * Set if we need phy clock workaround for 440gx | 305 | * Set if we need phy clock workaround for 440gx |
306 | */ | 306 | */ |
307 | #define EMAC_FTR_440GX_PHY_CLK_FIX 0x00000080 | 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 | /* Right now, we don't quite handle the always/possible masks on the | 314 | /* Right now, we don't quite handle the always/possible masks on the |
@@ -328,7 +332,7 @@ enum { | |||
328 | #ifdef CONFIG_IBM_NEW_EMAC_RGMII | 332 | #ifdef CONFIG_IBM_NEW_EMAC_RGMII |
329 | EMAC_FTR_HAS_RGMII | | 333 | EMAC_FTR_HAS_RGMII | |
330 | #endif | 334 | #endif |
331 | 0, | 335 | EMAC_FTR_440EP_PHY_CLK_FIX, |
332 | }; | 336 | }; |
333 | 337 | ||
334 | static inline int emac_has_feature(struct emac_instance *dev, | 338 | static inline int emac_has_feature(struct emac_instance *dev, |