diff options
author | Kim Phillips <kim.phillips@freescale.com> | 2007-04-13 02:26:03 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-04-28 11:01:04 -0400 |
commit | 728de4c927a3544b6d3da331b634035d4c75ca17 (patch) | |
tree | 5f05e0b318de9c1d517bd7bbca5964249c7cc885 /drivers | |
parent | a999589ccaae16472531e0616f23826ad097aa40 (diff) |
ucc_geth: migrate ucc_geth to phylib
migrate ucc_geth to use the common phylib code.
There are several side effects from doing this:
o deprecate 'interface' property specification present
in some old device tree source files in
favour of a split 'max-speed' and 'interface-type'
description to appropriately match definitions
in include/linux/phy.h. Note that 'interface' property
is still honoured if max-speed or interface-type
are not present (backward compatible).
o compile-time CONFIG_UGETH_HAS_GIGA is eliminated
in favour of probe time speed derivation logic.
o adjust_link streamlined to only operate on maccfg2
and upsmr.r10m, instead of reapplying static initial
values related to the interface-type.
o Addition of UEC MDIO of_platform driver requires
platform code add 'mdio' type to id list
prior to calling of_platform_bus_probe (separate patch).
o ucc_struct_init introduced to reduce ucc_geth_startup
complexity.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/Kconfig | 4 | ||||
-rw-r--r-- | drivers/net/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ucc_geth.c | 814 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 108 | ||||
-rw-r--r-- | drivers/net/ucc_geth_mii.c | 279 | ||||
-rw-r--r-- | drivers/net/ucc_geth_mii.h | 100 | ||||
-rw-r--r-- | drivers/net/ucc_geth_phy.c | 785 | ||||
-rw-r--r-- | drivers/net/ucc_geth_phy.h | 217 |
8 files changed, 659 insertions, 1650 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ee920ad1a5f5..87d69752d86a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2296,10 +2296,6 @@ config UGETH_TX_ON_DEMOND | |||
2296 | bool "Transmit on Demond support" | 2296 | bool "Transmit on Demond support" |
2297 | depends on UCC_GETH | 2297 | depends on UCC_GETH |
2298 | 2298 | ||
2299 | config UGETH_HAS_GIGA | ||
2300 | bool | ||
2301 | depends on UCC_GETH && PPC_MPC836x | ||
2302 | |||
2303 | config MV643XX_ETH | 2299 | config MV643XX_ETH |
2304 | tristate "MV-643XX Ethernet support" | 2300 | tristate "MV-643XX Ethernet support" |
2305 | depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32) | 2301 | depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32) |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 58527322a39d..59c0459a037c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \ | |||
18 | gianfar_sysfs.o | 18 | gianfar_sysfs.o |
19 | 19 | ||
20 | obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o | 20 | obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o |
21 | ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o | 21 | ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o |
22 | 22 | ||
23 | # | 23 | # |
24 | # link order important here | 24 | # link order important here |
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 639e1e6913bf..d93cfde663e9 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/fsl_devices.h> | 29 | #include <linux/fsl_devices.h> |
30 | #include <linux/ethtool.h> | 30 | #include <linux/ethtool.h> |
31 | #include <linux/mii.h> | 31 | #include <linux/mii.h> |
32 | #include <linux/phy.h> | ||
32 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
33 | 34 | ||
34 | #include <asm/of_platform.h> | 35 | #include <asm/of_platform.h> |
@@ -41,7 +42,7 @@ | |||
41 | #include <asm/ucc_fast.h> | 42 | #include <asm/ucc_fast.h> |
42 | 43 | ||
43 | #include "ucc_geth.h" | 44 | #include "ucc_geth.h" |
44 | #include "ucc_geth_phy.h" | 45 | #include "ucc_geth_mii.h" |
45 | 46 | ||
46 | #undef DEBUG | 47 | #undef DEBUG |
47 | 48 | ||
@@ -73,22 +74,13 @@ static struct ucc_geth_info ugeth_primary_info = { | |||
73 | .bd_mem_part = MEM_PART_SYSTEM, | 74 | .bd_mem_part = MEM_PART_SYSTEM, |
74 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, | 75 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, |
75 | .max_rx_buf_length = 1536, | 76 | .max_rx_buf_length = 1536, |
76 | /* FIXME: should be changed in run time for 1G and 100M */ | 77 | /* adjusted at startup if max-speed 1000 */ |
77 | #ifdef CONFIG_UGETH_HAS_GIGA | ||
78 | .urfs = UCC_GETH_URFS_GIGA_INIT, | ||
79 | .urfet = UCC_GETH_URFET_GIGA_INIT, | ||
80 | .urfset = UCC_GETH_URFSET_GIGA_INIT, | ||
81 | .utfs = UCC_GETH_UTFS_GIGA_INIT, | ||
82 | .utfet = UCC_GETH_UTFET_GIGA_INIT, | ||
83 | .utftt = UCC_GETH_UTFTT_GIGA_INIT, | ||
84 | #else | ||
85 | .urfs = UCC_GETH_URFS_INIT, | 78 | .urfs = UCC_GETH_URFS_INIT, |
86 | .urfet = UCC_GETH_URFET_INIT, | 79 | .urfet = UCC_GETH_URFET_INIT, |
87 | .urfset = UCC_GETH_URFSET_INIT, | 80 | .urfset = UCC_GETH_URFSET_INIT, |
88 | .utfs = UCC_GETH_UTFS_INIT, | 81 | .utfs = UCC_GETH_UTFS_INIT, |
89 | .utfet = UCC_GETH_UTFET_INIT, | 82 | .utfet = UCC_GETH_UTFET_INIT, |
90 | .utftt = UCC_GETH_UTFTT_INIT, | 83 | .utftt = UCC_GETH_UTFTT_INIT, |
91 | #endif | ||
92 | .ufpt = 256, | 84 | .ufpt = 256, |
93 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, | 85 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, |
94 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, | 86 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, |
@@ -217,70 +209,6 @@ static struct list_head *dequeue(struct list_head *lh) | |||
217 | } | 209 | } |
218 | } | 210 | } |
219 | 211 | ||
220 | static int get_interface_details(enum enet_interface enet_interface, | ||
221 | enum enet_speed *speed, | ||
222 | int *r10m, | ||
223 | int *rmm, | ||
224 | int *rpm, | ||
225 | int *tbi, int *limited_to_full_duplex) | ||
226 | { | ||
227 | /* Analyze enet_interface according to Interface Mode | ||
228 | Configuration table */ | ||
229 | switch (enet_interface) { | ||
230 | case ENET_10_MII: | ||
231 | *speed = ENET_SPEED_10BT; | ||
232 | break; | ||
233 | case ENET_10_RMII: | ||
234 | *speed = ENET_SPEED_10BT; | ||
235 | *r10m = 1; | ||
236 | *rmm = 1; | ||
237 | break; | ||
238 | case ENET_10_RGMII: | ||
239 | *speed = ENET_SPEED_10BT; | ||
240 | *rpm = 1; | ||
241 | *r10m = 1; | ||
242 | *limited_to_full_duplex = 1; | ||
243 | break; | ||
244 | case ENET_100_MII: | ||
245 | *speed = ENET_SPEED_100BT; | ||
246 | break; | ||
247 | case ENET_100_RMII: | ||
248 | *speed = ENET_SPEED_100BT; | ||
249 | *rmm = 1; | ||
250 | break; | ||
251 | case ENET_100_RGMII: | ||
252 | *speed = ENET_SPEED_100BT; | ||
253 | *rpm = 1; | ||
254 | *limited_to_full_duplex = 1; | ||
255 | break; | ||
256 | case ENET_1000_GMII: | ||
257 | *speed = ENET_SPEED_1000BT; | ||
258 | *limited_to_full_duplex = 1; | ||
259 | break; | ||
260 | case ENET_1000_RGMII: | ||
261 | *speed = ENET_SPEED_1000BT; | ||
262 | *rpm = 1; | ||
263 | *limited_to_full_duplex = 1; | ||
264 | break; | ||
265 | case ENET_1000_TBI: | ||
266 | *speed = ENET_SPEED_1000BT; | ||
267 | *tbi = 1; | ||
268 | *limited_to_full_duplex = 1; | ||
269 | break; | ||
270 | case ENET_1000_RTBI: | ||
271 | *speed = ENET_SPEED_1000BT; | ||
272 | *rpm = 1; | ||
273 | *tbi = 1; | ||
274 | *limited_to_full_duplex = 1; | ||
275 | break; | ||
276 | default: | ||
277 | return -EINVAL; | ||
278 | break; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) | 212 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) |
285 | { | 213 | { |
286 | struct sk_buff *skb = NULL; | 214 | struct sk_buff *skb = NULL; |
@@ -758,24 +686,6 @@ static void dump_regs(struct ucc_geth_private *ugeth) | |||
758 | ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", | 686 | ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", |
759 | (u32) & ugeth->ug_regs->hafdup, | 687 | (u32) & ugeth->ug_regs->hafdup, |
760 | in_be32(&ugeth->ug_regs->hafdup)); | 688 | in_be32(&ugeth->ug_regs->hafdup)); |
761 | ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", | ||
762 | (u32) & ugeth->ug_regs->miimng.miimcfg, | ||
763 | in_be32(&ugeth->ug_regs->miimng.miimcfg)); | ||
764 | ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", | ||
765 | (u32) & ugeth->ug_regs->miimng.miimcom, | ||
766 | in_be32(&ugeth->ug_regs->miimng.miimcom)); | ||
767 | ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", | ||
768 | (u32) & ugeth->ug_regs->miimng.miimadd, | ||
769 | in_be32(&ugeth->ug_regs->miimng.miimadd)); | ||
770 | ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", | ||
771 | (u32) & ugeth->ug_regs->miimng.miimcon, | ||
772 | in_be32(&ugeth->ug_regs->miimng.miimcon)); | ||
773 | ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", | ||
774 | (u32) & ugeth->ug_regs->miimng.miimstat, | ||
775 | in_be32(&ugeth->ug_regs->miimng.miimstat)); | ||
776 | ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", | ||
777 | (u32) & ugeth->ug_regs->miimng.miimind, | ||
778 | in_be32(&ugeth->ug_regs->miimng.miimind)); | ||
779 | ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", | 689 | ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", |
780 | (u32) & ugeth->ug_regs->ifctl, | 690 | (u32) & ugeth->ug_regs->ifctl, |
781 | in_be32(&ugeth->ug_regs->ifctl)); | 691 | in_be32(&ugeth->ug_regs->ifctl)); |
@@ -1425,27 +1335,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0, | |||
1425 | return 0; | 1335 | return 0; |
1426 | } | 1336 | } |
1427 | 1337 | ||
1428 | static int init_mac_duplex_mode(int full_duplex, | ||
1429 | int limited_to_full_duplex, | ||
1430 | volatile u32 *maccfg2_register) | ||
1431 | { | ||
1432 | u32 value = 0; | ||
1433 | |||
1434 | /* some interfaces must work in full duplex mode */ | ||
1435 | if ((full_duplex == 0) && (limited_to_full_duplex == 1)) | ||
1436 | return -EINVAL; | ||
1437 | |||
1438 | value = in_be32(maccfg2_register); | ||
1439 | |||
1440 | if (full_duplex) | ||
1441 | value |= MACCFG2_FDX; | ||
1442 | else | ||
1443 | value &= ~MACCFG2_FDX; | ||
1444 | |||
1445 | out_be32(maccfg2_register, value); | ||
1446 | return 0; | ||
1447 | } | ||
1448 | |||
1449 | static int init_check_frame_length_mode(int length_check, | 1338 | static int init_check_frame_length_mode(int length_check, |
1450 | volatile u32 *maccfg2_register) | 1339 | volatile u32 *maccfg2_register) |
1451 | { | 1340 | { |
@@ -1477,40 +1366,6 @@ static int init_preamble_length(u8 preamble_length, | |||
1477 | return 0; | 1366 | return 0; |
1478 | } | 1367 | } |
1479 | 1368 | ||
1480 | static int init_mii_management_configuration(int reset_mgmt, | ||
1481 | int preamble_supress, | ||
1482 | volatile u32 *miimcfg_register, | ||
1483 | volatile u32 *miimind_register) | ||
1484 | { | ||
1485 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
1486 | u32 value = 0; | ||
1487 | |||
1488 | value = in_be32(miimcfg_register); | ||
1489 | if (reset_mgmt) { | ||
1490 | value |= MIIMCFG_RESET_MANAGEMENT; | ||
1491 | out_be32(miimcfg_register, value); | ||
1492 | } | ||
1493 | |||
1494 | value = 0; | ||
1495 | |||
1496 | if (preamble_supress) | ||
1497 | value |= MIIMCFG_NO_PREAMBLE; | ||
1498 | |||
1499 | value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; | ||
1500 | out_be32(miimcfg_register, value); | ||
1501 | |||
1502 | /* Wait until the bus is free */ | ||
1503 | while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) | ||
1504 | cpu_relax(); | ||
1505 | |||
1506 | if (timeout <= 0) { | ||
1507 | ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); | ||
1508 | return -ETIMEDOUT; | ||
1509 | } | ||
1510 | |||
1511 | return 0; | ||
1512 | } | ||
1513 | |||
1514 | static int init_rx_parameters(int reject_broadcast, | 1369 | static int init_rx_parameters(int reject_broadcast, |
1515 | int receive_short_frames, | 1370 | int receive_short_frames, |
1516 | int promiscuous, volatile u32 *upsmr_register) | 1371 | int promiscuous, volatile u32 *upsmr_register) |
@@ -1570,10 +1425,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1570 | struct ucc_geth_info *ug_info; | 1425 | struct ucc_geth_info *ug_info; |
1571 | struct ucc_geth *ug_regs; | 1426 | struct ucc_geth *ug_regs; |
1572 | struct ucc_fast *uf_regs; | 1427 | struct ucc_fast *uf_regs; |
1573 | enum enet_speed speed; | 1428 | int ret_val; |
1574 | int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = | 1429 | u32 upsmr, maccfg2, tbiBaseAddress; |
1575 | 0, limited_to_full_duplex = 0; | ||
1576 | u32 upsmr, maccfg2, utbipar, tbiBaseAddress; | ||
1577 | u16 value; | 1430 | u16 value; |
1578 | 1431 | ||
1579 | ugeth_vdbg("%s: IN", __FUNCTION__); | 1432 | ugeth_vdbg("%s: IN", __FUNCTION__); |
@@ -1582,24 +1435,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1582 | ug_regs = ugeth->ug_regs; | 1435 | ug_regs = ugeth->ug_regs; |
1583 | uf_regs = ugeth->uccf->uf_regs; | 1436 | uf_regs = ugeth->uccf->uf_regs; |
1584 | 1437 | ||
1585 | /* Analyze enet_interface according to Interface Mode Configuration | ||
1586 | table */ | ||
1587 | ret_val = | ||
1588 | get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, | ||
1589 | &rpm, &tbi, &limited_to_full_duplex); | ||
1590 | if (ret_val != 0) { | ||
1591 | ugeth_err | ||
1592 | ("%s: half duplex not supported in requested configuration.", | ||
1593 | __FUNCTION__); | ||
1594 | return ret_val; | ||
1595 | } | ||
1596 | |||
1597 | /* Set MACCFG2 */ | 1438 | /* Set MACCFG2 */ |
1598 | maccfg2 = in_be32(&ug_regs->maccfg2); | 1439 | maccfg2 = in_be32(&ug_regs->maccfg2); |
1599 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; | 1440 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; |
1600 | if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) | 1441 | if ((ugeth->max_speed == SPEED_10) || |
1442 | (ugeth->max_speed == SPEED_100)) | ||
1601 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; | 1443 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; |
1602 | else if (speed == ENET_SPEED_1000BT) | 1444 | else if (ugeth->max_speed == SPEED_1000) |
1603 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; | 1445 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; |
1604 | maccfg2 |= ug_info->padAndCrc; | 1446 | maccfg2 |= ug_info->padAndCrc; |
1605 | out_be32(&ug_regs->maccfg2, maccfg2); | 1447 | out_be32(&ug_regs->maccfg2, maccfg2); |
@@ -1607,54 +1449,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1607 | /* Set UPSMR */ | 1449 | /* Set UPSMR */ |
1608 | upsmr = in_be32(&uf_regs->upsmr); | 1450 | upsmr = in_be32(&uf_regs->upsmr); |
1609 | upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); | 1451 | upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); |
1610 | if (rpm) | 1452 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || |
1453 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | ||
1454 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | ||
1455 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1611 | upsmr |= UPSMR_RPM; | 1456 | upsmr |= UPSMR_RPM; |
1612 | if (r10m) | 1457 | switch (ugeth->max_speed) { |
1613 | upsmr |= UPSMR_R10M; | 1458 | case SPEED_10: |
1614 | if (tbi) | 1459 | upsmr |= UPSMR_R10M; |
1460 | /* FALLTHROUGH */ | ||
1461 | case SPEED_100: | ||
1462 | if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) | ||
1463 | upsmr |= UPSMR_RMM; | ||
1464 | } | ||
1465 | } | ||
1466 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || | ||
1467 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1615 | upsmr |= UPSMR_TBIM; | 1468 | upsmr |= UPSMR_TBIM; |
1616 | if (rmm) | 1469 | } |
1617 | upsmr |= UPSMR_RMM; | ||
1618 | out_be32(&uf_regs->upsmr, upsmr); | 1470 | out_be32(&uf_regs->upsmr, upsmr); |
1619 | 1471 | ||
1620 | /* Set UTBIPAR */ | ||
1621 | utbipar = in_be32(&ug_regs->utbipar); | ||
1622 | utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; | ||
1623 | if (tbi) | ||
1624 | utbipar |= | ||
1625 | (ug_info->phy_address + | ||
1626 | ugeth->ug_info->uf_info. | ||
1627 | ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; | ||
1628 | else | ||
1629 | utbipar |= | ||
1630 | (0x10 + | ||
1631 | ugeth->ug_info->uf_info. | ||
1632 | ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; | ||
1633 | out_be32(&ug_regs->utbipar, utbipar); | ||
1634 | |||
1635 | /* Disable autonegotiation in tbi mode, because by default it | 1472 | /* Disable autonegotiation in tbi mode, because by default it |
1636 | comes up in autonegotiation mode. */ | 1473 | comes up in autonegotiation mode. */ |
1637 | /* Note that this depends on proper setting in utbipar register. */ | 1474 | /* Note that this depends on proper setting in utbipar register. */ |
1638 | if (tbi) { | 1475 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || |
1476 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1639 | tbiBaseAddress = in_be32(&ug_regs->utbipar); | 1477 | tbiBaseAddress = in_be32(&ug_regs->utbipar); |
1640 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; | 1478 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; |
1641 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; | 1479 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; |
1642 | value = | 1480 | value = ugeth->phydev->bus->read(ugeth->phydev->bus, |
1643 | ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, | 1481 | (u8) tbiBaseAddress, ENET_TBI_MII_CR); |
1644 | ENET_TBI_MII_CR); | ||
1645 | value &= ~0x1000; /* Turn off autonegotiation */ | 1482 | value &= ~0x1000; /* Turn off autonegotiation */ |
1646 | ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, | 1483 | ugeth->phydev->bus->write(ugeth->phydev->bus, |
1647 | ENET_TBI_MII_CR, value); | 1484 | (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); |
1648 | } | ||
1649 | |||
1650 | ret_val = init_mac_duplex_mode(1, | ||
1651 | limited_to_full_duplex, | ||
1652 | &ug_regs->maccfg2); | ||
1653 | if (ret_val != 0) { | ||
1654 | ugeth_err | ||
1655 | ("%s: half duplex not supported in requested configuration.", | ||
1656 | __FUNCTION__); | ||
1657 | return ret_val; | ||
1658 | } | 1485 | } |
1659 | 1486 | ||
1660 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); | 1487 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); |
@@ -1676,76 +1503,88 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1676 | * function converts those variables into the appropriate | 1503 | * function converts those variables into the appropriate |
1677 | * register values, and can bring down the device if needed. | 1504 | * register values, and can bring down the device if needed. |
1678 | */ | 1505 | */ |
1506 | |||
1679 | static void adjust_link(struct net_device *dev) | 1507 | static void adjust_link(struct net_device *dev) |
1680 | { | 1508 | { |
1681 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 1509 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
1682 | struct ucc_geth *ug_regs; | 1510 | struct ucc_geth *ug_regs; |
1683 | u32 tempval; | 1511 | struct ucc_fast *uf_regs; |
1684 | struct ugeth_mii_info *mii_info = ugeth->mii_info; | 1512 | struct phy_device *phydev = ugeth->phydev; |
1513 | unsigned long flags; | ||
1514 | int new_state = 0; | ||
1685 | 1515 | ||
1686 | ug_regs = ugeth->ug_regs; | 1516 | ug_regs = ugeth->ug_regs; |
1517 | uf_regs = ugeth->uccf->uf_regs; | ||
1687 | 1518 | ||
1688 | if (mii_info->link) { | 1519 | spin_lock_irqsave(&ugeth->lock, flags); |
1520 | |||
1521 | if (phydev->link) { | ||
1522 | u32 tempval = in_be32(&ug_regs->maccfg2); | ||
1523 | u32 upsmr = in_be32(&uf_regs->upsmr); | ||
1689 | /* Now we make sure that we can be in full duplex mode. | 1524 | /* Now we make sure that we can be in full duplex mode. |
1690 | * If not, we operate in half-duplex mode. */ | 1525 | * If not, we operate in half-duplex mode. */ |
1691 | if (mii_info->duplex != ugeth->oldduplex) { | 1526 | if (phydev->duplex != ugeth->oldduplex) { |
1692 | if (!(mii_info->duplex)) { | 1527 | new_state = 1; |
1693 | tempval = in_be32(&ug_regs->maccfg2); | 1528 | if (!(phydev->duplex)) |
1694 | tempval &= ~(MACCFG2_FDX); | 1529 | tempval &= ~(MACCFG2_FDX); |
1695 | out_be32(&ug_regs->maccfg2, tempval); | 1530 | else |
1696 | |||
1697 | ugeth_info("%s: Half Duplex", dev->name); | ||
1698 | } else { | ||
1699 | tempval = in_be32(&ug_regs->maccfg2); | ||
1700 | tempval |= MACCFG2_FDX; | 1531 | tempval |= MACCFG2_FDX; |
1701 | out_be32(&ug_regs->maccfg2, tempval); | 1532 | ugeth->oldduplex = phydev->duplex; |
1702 | |||
1703 | ugeth_info("%s: Full Duplex", dev->name); | ||
1704 | } | ||
1705 | |||
1706 | ugeth->oldduplex = mii_info->duplex; | ||
1707 | } | 1533 | } |
1708 | 1534 | ||
1709 | if (mii_info->speed != ugeth->oldspeed) { | 1535 | if (phydev->speed != ugeth->oldspeed) { |
1710 | switch (mii_info->speed) { | 1536 | new_state = 1; |
1711 | case 1000: | 1537 | switch (phydev->speed) { |
1712 | ugeth->ug_info->enet_interface = ENET_1000_RGMII; | 1538 | case SPEED_1000: |
1713 | break; | 1539 | tempval = ((tempval & |
1714 | case 100: | 1540 | ~(MACCFG2_INTERFACE_MODE_MASK)) | |
1715 | ugeth->ug_info->enet_interface = ENET_100_RGMII; | 1541 | MACCFG2_INTERFACE_MODE_BYTE); |
1716 | break; | 1542 | break; |
1717 | case 10: | 1543 | case SPEED_100: |
1718 | ugeth->ug_info->enet_interface = ENET_10_RGMII; | 1544 | case SPEED_10: |
1545 | tempval = ((tempval & | ||
1546 | ~(MACCFG2_INTERFACE_MODE_MASK)) | | ||
1547 | MACCFG2_INTERFACE_MODE_NIBBLE); | ||
1548 | /* if reduced mode, re-set UPSMR.R10M */ | ||
1549 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || | ||
1550 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | ||
1551 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | ||
1552 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1553 | if (phydev->speed == SPEED_10) | ||
1554 | upsmr |= UPSMR_R10M; | ||
1555 | else | ||
1556 | upsmr &= ~(UPSMR_R10M); | ||
1557 | } | ||
1719 | break; | 1558 | break; |
1720 | default: | 1559 | default: |
1721 | ugeth_warn | 1560 | if (netif_msg_link(ugeth)) |
1722 | ("%s: Ack! Speed (%d) is not 10/100/1000!", | 1561 | ugeth_warn( |
1723 | dev->name, mii_info->speed); | 1562 | "%s: Ack! Speed (%d) is not 10/100/1000!", |
1563 | dev->name, phydev->speed); | ||
1724 | break; | 1564 | break; |
1725 | } | 1565 | } |
1726 | adjust_enet_interface(ugeth); | 1566 | ugeth->oldspeed = phydev->speed; |
1727 | |||
1728 | ugeth_info("%s: Speed %dBT", dev->name, | ||
1729 | mii_info->speed); | ||
1730 | |||
1731 | ugeth->oldspeed = mii_info->speed; | ||
1732 | } | 1567 | } |
1733 | 1568 | ||
1569 | out_be32(&ug_regs->maccfg2, tempval); | ||
1570 | out_be32(&uf_regs->upsmr, upsmr); | ||
1571 | |||
1734 | if (!ugeth->oldlink) { | 1572 | if (!ugeth->oldlink) { |
1735 | ugeth_info("%s: Link is up", dev->name); | 1573 | new_state = 1; |
1736 | ugeth->oldlink = 1; | 1574 | ugeth->oldlink = 1; |
1737 | netif_carrier_on(dev); | ||
1738 | netif_schedule(dev); | 1575 | netif_schedule(dev); |
1739 | } | 1576 | } |
1740 | } else { | 1577 | } else if (ugeth->oldlink) { |
1741 | if (ugeth->oldlink) { | 1578 | new_state = 1; |
1742 | ugeth_info("%s: Link is down", dev->name); | ||
1743 | ugeth->oldlink = 0; | 1579 | ugeth->oldlink = 0; |
1744 | ugeth->oldspeed = 0; | 1580 | ugeth->oldspeed = 0; |
1745 | ugeth->oldduplex = -1; | 1581 | ugeth->oldduplex = -1; |
1746 | netif_carrier_off(dev); | ||
1747 | } | ||
1748 | } | 1582 | } |
1583 | |||
1584 | if (new_state && netif_msg_link(ugeth)) | ||
1585 | phy_print_status(phydev); | ||
1586 | |||
1587 | spin_unlock_irqrestore(&ugeth->lock, flags); | ||
1749 | } | 1588 | } |
1750 | 1589 | ||
1751 | /* Configure the PHY for dev. | 1590 | /* Configure the PHY for dev. |
@@ -1753,94 +1592,40 @@ static void adjust_link(struct net_device *dev) | |||
1753 | */ | 1592 | */ |
1754 | static int init_phy(struct net_device *dev) | 1593 | static int init_phy(struct net_device *dev) |
1755 | { | 1594 | { |
1756 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 1595 | struct ucc_geth_private *priv = netdev_priv(dev); |
1757 | struct phy_info *curphy; | 1596 | struct phy_device *phydev; |
1758 | struct ucc_mii_mng *mii_regs; | 1597 | char phy_id[BUS_ID_SIZE]; |
1759 | struct ugeth_mii_info *mii_info; | ||
1760 | int err; | ||
1761 | 1598 | ||
1762 | mii_regs = &ugeth->ug_regs->miimng; | 1599 | priv->oldlink = 0; |
1600 | priv->oldspeed = 0; | ||
1601 | priv->oldduplex = -1; | ||
1763 | 1602 | ||
1764 | ugeth->oldlink = 0; | 1603 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, |
1765 | ugeth->oldspeed = 0; | 1604 | priv->ug_info->phy_address); |
1766 | ugeth->oldduplex = -1; | ||
1767 | 1605 | ||
1768 | mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); | 1606 | phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); |
1769 | 1607 | ||
1770 | if (NULL == mii_info) { | 1608 | if (IS_ERR(phydev)) { |
1771 | ugeth_err("%s: Could not allocate mii_info", dev->name); | 1609 | printk("%s: Could not attach to PHY\n", dev->name); |
1772 | return -ENOMEM; | 1610 | return PTR_ERR(phydev); |
1773 | } | 1611 | } |
1774 | 1612 | ||
1775 | mii_info->mii_regs = mii_regs; | 1613 | phydev->supported &= (ADVERTISED_10baseT_Half | |
1776 | mii_info->speed = SPEED_1000; | ||
1777 | mii_info->duplex = DUPLEX_FULL; | ||
1778 | mii_info->pause = 0; | ||
1779 | mii_info->link = 0; | ||
1780 | |||
1781 | mii_info->advertising = (ADVERTISED_10baseT_Half | | ||
1782 | ADVERTISED_10baseT_Full | | 1614 | ADVERTISED_10baseT_Full | |
1783 | ADVERTISED_100baseT_Half | | 1615 | ADVERTISED_100baseT_Half | |
1784 | ADVERTISED_100baseT_Full | | 1616 | ADVERTISED_100baseT_Full); |
1785 | ADVERTISED_1000baseT_Full); | ||
1786 | mii_info->autoneg = 1; | ||
1787 | |||
1788 | mii_info->mii_id = ugeth->ug_info->phy_address; | ||
1789 | |||
1790 | mii_info->dev = dev; | ||
1791 | 1617 | ||
1792 | mii_info->mdio_read = &read_phy_reg; | 1618 | if (priv->max_speed == SPEED_1000) |
1793 | mii_info->mdio_write = &write_phy_reg; | 1619 | phydev->supported |= ADVERTISED_1000baseT_Full; |
1794 | 1620 | ||
1795 | spin_lock_init(&mii_info->mdio_lock); | 1621 | phydev->advertising = phydev->supported; |
1796 | 1622 | ||
1797 | ugeth->mii_info = mii_info; | 1623 | priv->phydev = phydev; |
1798 | |||
1799 | spin_lock_irq(&ugeth->lock); | ||
1800 | |||
1801 | /* Set this UCC to be the master of the MII managment */ | ||
1802 | ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); | ||
1803 | |||
1804 | if (init_mii_management_configuration(1, | ||
1805 | ugeth->ug_info-> | ||
1806 | miiPreambleSupress, | ||
1807 | &mii_regs->miimcfg, | ||
1808 | &mii_regs->miimind)) { | ||
1809 | ugeth_err("%s: The MII Bus is stuck!", dev->name); | ||
1810 | err = -1; | ||
1811 | goto bus_fail; | ||
1812 | } | ||
1813 | |||
1814 | spin_unlock_irq(&ugeth->lock); | ||
1815 | |||
1816 | /* get info for this PHY */ | ||
1817 | curphy = get_phy_info(ugeth->mii_info); | ||
1818 | |||
1819 | if (curphy == NULL) { | ||
1820 | ugeth_err("%s: No PHY found", dev->name); | ||
1821 | err = -1; | ||
1822 | goto no_phy; | ||
1823 | } | ||
1824 | |||
1825 | mii_info->phyinfo = curphy; | ||
1826 | |||
1827 | /* Run the commands which initialize the PHY */ | ||
1828 | if (curphy->init) { | ||
1829 | err = curphy->init(ugeth->mii_info); | ||
1830 | if (err) | ||
1831 | goto phy_init_fail; | ||
1832 | } | ||
1833 | 1624 | ||
1834 | return 0; | 1625 | return 0; |
1835 | |||
1836 | phy_init_fail: | ||
1837 | no_phy: | ||
1838 | bus_fail: | ||
1839 | kfree(mii_info); | ||
1840 | |||
1841 | return err; | ||
1842 | } | 1626 | } |
1843 | 1627 | ||
1628 | |||
1844 | #ifdef CONFIG_UGETH_TX_ON_DEMOND | 1629 | #ifdef CONFIG_UGETH_TX_ON_DEMOND |
1845 | static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) | 1630 | static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) |
1846 | { | 1631 | { |
@@ -2487,6 +2272,7 @@ static void ucc_geth_set_multi(struct net_device *dev) | |||
2487 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) | 2272 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) |
2488 | { | 2273 | { |
2489 | struct ucc_geth *ug_regs = ugeth->ug_regs; | 2274 | struct ucc_geth *ug_regs = ugeth->ug_regs; |
2275 | struct phy_device *phydev = ugeth->phydev; | ||
2490 | u32 tempval; | 2276 | u32 tempval; |
2491 | 2277 | ||
2492 | ugeth_vdbg("%s: IN", __FUNCTION__); | 2278 | ugeth_vdbg("%s: IN", __FUNCTION__); |
@@ -2495,8 +2281,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) | |||
2495 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); | 2281 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); |
2496 | 2282 | ||
2497 | /* Tell the kernel the link is down */ | 2283 | /* Tell the kernel the link is down */ |
2498 | ugeth->mii_info->link = 0; | 2284 | phy_stop(phydev); |
2499 | adjust_link(ugeth->dev); | ||
2500 | 2285 | ||
2501 | /* Mask all interrupts */ | 2286 | /* Mask all interrupts */ |
2502 | out_be32(ugeth->uccf->p_ucce, 0x00000000); | 2287 | out_be32(ugeth->uccf->p_ucce, 0x00000000); |
@@ -2509,46 +2294,16 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) | |||
2509 | tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); | 2294 | tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); |
2510 | out_be32(&ug_regs->maccfg1, tempval); | 2295 | out_be32(&ug_regs->maccfg1, tempval); |
2511 | 2296 | ||
2512 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
2513 | /* Clear any pending interrupts */ | ||
2514 | mii_clear_phy_interrupt(ugeth->mii_info); | ||
2515 | |||
2516 | /* Disable PHY Interrupts */ | ||
2517 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
2518 | MII_INTERRUPT_DISABLED); | ||
2519 | } | ||
2520 | |||
2521 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); | 2297 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); |
2522 | 2298 | ||
2523 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
2524 | free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); | ||
2525 | } else { | ||
2526 | del_timer_sync(&ugeth->phy_info_timer); | ||
2527 | } | ||
2528 | |||
2529 | ucc_geth_memclean(ugeth); | 2299 | ucc_geth_memclean(ugeth); |
2530 | } | 2300 | } |
2531 | 2301 | ||
2532 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | 2302 | static int ucc_struct_init(struct ucc_geth_private *ugeth) |
2533 | { | 2303 | { |
2534 | struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; | ||
2535 | struct ucc_geth_init_pram *p_init_enet_pram; | ||
2536 | struct ucc_fast_private *uccf; | ||
2537 | struct ucc_geth_info *ug_info; | 2304 | struct ucc_geth_info *ug_info; |
2538 | struct ucc_fast_info *uf_info; | 2305 | struct ucc_fast_info *uf_info; |
2539 | struct ucc_fast *uf_regs; | 2306 | int i; |
2540 | struct ucc_geth *ug_regs; | ||
2541 | int ret_val = -EINVAL; | ||
2542 | u32 remoder = UCC_GETH_REMODER_INIT; | ||
2543 | u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; | ||
2544 | u32 ifstat, i, j, size, l2qt, l3qt, length; | ||
2545 | u16 temoder = UCC_GETH_TEMODER_INIT; | ||
2546 | u16 test; | ||
2547 | u8 function_code = 0; | ||
2548 | u8 *bd, *endOfRing; | ||
2549 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | ||
2550 | |||
2551 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
2552 | 2307 | ||
2553 | ug_info = ugeth->ug_info; | 2308 | ug_info = ugeth->ug_info; |
2554 | uf_info = &ug_info->uf_info; | 2309 | uf_info = &ug_info->uf_info; |
@@ -2647,12 +2402,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
2647 | for (i = 0; i < ug_info->numQueuesTx; i++) | 2402 | for (i = 0; i < ug_info->numQueuesTx; i++) |
2648 | uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); | 2403 | uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); |
2649 | /* Initialize the general fast UCC block. */ | 2404 | /* Initialize the general fast UCC block. */ |
2650 | if (ucc_fast_init(uf_info, &uccf)) { | 2405 | if (ucc_fast_init(uf_info, &ugeth->uccf)) { |
2651 | ugeth_err("%s: Failed to init uccf.", __FUNCTION__); | 2406 | ugeth_err("%s: Failed to init uccf.", __FUNCTION__); |
2652 | ucc_geth_memclean(ugeth); | 2407 | ucc_geth_memclean(ugeth); |
2653 | return -ENOMEM; | 2408 | return -ENOMEM; |
2654 | } | 2409 | } |
2655 | ugeth->uccf = uccf; | 2410 | |
2411 | ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); | ||
2412 | |||
2413 | return 0; | ||
2414 | } | ||
2415 | |||
2416 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | ||
2417 | { | ||
2418 | struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; | ||
2419 | struct ucc_geth_init_pram *p_init_enet_pram; | ||
2420 | struct ucc_fast_private *uccf; | ||
2421 | struct ucc_geth_info *ug_info; | ||
2422 | struct ucc_fast_info *uf_info; | ||
2423 | struct ucc_fast *uf_regs; | ||
2424 | struct ucc_geth *ug_regs; | ||
2425 | int ret_val = -EINVAL; | ||
2426 | u32 remoder = UCC_GETH_REMODER_INIT; | ||
2427 | u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; | ||
2428 | u32 ifstat, i, j, size, l2qt, l3qt, length; | ||
2429 | u16 temoder = UCC_GETH_TEMODER_INIT; | ||
2430 | u16 test; | ||
2431 | u8 function_code = 0; | ||
2432 | u8 *bd, *endOfRing; | ||
2433 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | ||
2434 | |||
2435 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
2436 | uccf = ugeth->uccf; | ||
2437 | ug_info = ugeth->ug_info; | ||
2438 | uf_info = &ug_info->uf_info; | ||
2439 | uf_regs = uccf->uf_regs; | ||
2440 | ug_regs = ugeth->ug_regs; | ||
2656 | 2441 | ||
2657 | switch (ug_info->numThreadsRx) { | 2442 | switch (ug_info->numThreadsRx) { |
2658 | case UCC_GETH_NUM_OF_THREADS_1: | 2443 | case UCC_GETH_NUM_OF_THREADS_1: |
@@ -2711,10 +2496,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
2711 | || (ug_info->vlanOperationNonTagged != | 2496 | || (ug_info->vlanOperationNonTagged != |
2712 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); | 2497 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); |
2713 | 2498 | ||
2714 | uf_regs = uccf->uf_regs; | ||
2715 | ug_regs = (struct ucc_geth *) (uccf->uf_regs); | ||
2716 | ugeth->ug_regs = ug_regs; | ||
2717 | |||
2718 | init_default_reg_vals(&uf_regs->upsmr, | 2499 | init_default_reg_vals(&uf_regs->upsmr, |
2719 | &ug_regs->maccfg1, &ug_regs->maccfg2); | 2500 | &ug_regs->maccfg1, &ug_regs->maccfg2); |
2720 | 2501 | ||
@@ -3841,128 +3622,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
3841 | return IRQ_HANDLED; | 3622 | return IRQ_HANDLED; |
3842 | } | 3623 | } |
3843 | 3624 | ||
3844 | static irqreturn_t phy_interrupt(int irq, void *dev_id) | ||
3845 | { | ||
3846 | struct net_device *dev = (struct net_device *)dev_id; | ||
3847 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
3848 | |||
3849 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
3850 | |||
3851 | /* Clear the interrupt */ | ||
3852 | mii_clear_phy_interrupt(ugeth->mii_info); | ||
3853 | |||
3854 | /* Disable PHY interrupts */ | ||
3855 | mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); | ||
3856 | |||
3857 | /* Schedule the phy change */ | ||
3858 | schedule_work(&ugeth->tq); | ||
3859 | |||
3860 | return IRQ_HANDLED; | ||
3861 | } | ||
3862 | |||
3863 | /* Scheduled by the phy_interrupt/timer to handle PHY changes */ | ||
3864 | static void ugeth_phy_change(struct work_struct *work) | ||
3865 | { | ||
3866 | struct ucc_geth_private *ugeth = | ||
3867 | container_of(work, struct ucc_geth_private, tq); | ||
3868 | struct net_device *dev = ugeth->dev; | ||
3869 | struct ucc_geth *ug_regs; | ||
3870 | int result = 0; | ||
3871 | |||
3872 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
3873 | |||
3874 | ug_regs = ugeth->ug_regs; | ||
3875 | |||
3876 | /* Delay to give the PHY a chance to change the | ||
3877 | * register state */ | ||
3878 | msleep(1); | ||
3879 | |||
3880 | /* Update the link, speed, duplex */ | ||
3881 | result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); | ||
3882 | |||
3883 | /* Adjust the known status as long as the link | ||
3884 | * isn't still coming up */ | ||
3885 | if ((0 == result) || (ugeth->mii_info->link == 0)) | ||
3886 | adjust_link(dev); | ||
3887 | |||
3888 | /* Reenable interrupts, if needed */ | ||
3889 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) | ||
3890 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
3891 | MII_INTERRUPT_ENABLED); | ||
3892 | } | ||
3893 | |||
3894 | /* Called every so often on systems that don't interrupt | ||
3895 | * the core for PHY changes */ | ||
3896 | static void ugeth_phy_timer(unsigned long data) | ||
3897 | { | ||
3898 | struct net_device *dev = (struct net_device *)data; | ||
3899 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
3900 | |||
3901 | schedule_work(&ugeth->tq); | ||
3902 | |||
3903 | mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); | ||
3904 | } | ||
3905 | |||
3906 | /* Keep trying aneg for some time | ||
3907 | * If, after GFAR_AN_TIMEOUT seconds, it has not | ||
3908 | * finished, we switch to forced. | ||
3909 | * Either way, once the process has completed, we either | ||
3910 | * request the interrupt, or switch the timer over to | ||
3911 | * using ugeth_phy_timer to check status */ | ||
3912 | static void ugeth_phy_startup_timer(unsigned long data) | ||
3913 | { | ||
3914 | struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; | ||
3915 | struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev); | ||
3916 | static int secondary = UGETH_AN_TIMEOUT; | ||
3917 | int result; | ||
3918 | |||
3919 | /* Configure the Auto-negotiation */ | ||
3920 | result = mii_info->phyinfo->config_aneg(mii_info); | ||
3921 | |||
3922 | /* If autonegotiation failed to start, and | ||
3923 | * we haven't timed out, reset the timer, and return */ | ||
3924 | if (result && secondary--) { | ||
3925 | mod_timer(&ugeth->phy_info_timer, jiffies + HZ); | ||
3926 | return; | ||
3927 | } else if (result) { | ||
3928 | /* Couldn't start autonegotiation. | ||
3929 | * Try switching to forced */ | ||
3930 | mii_info->autoneg = 0; | ||
3931 | result = mii_info->phyinfo->config_aneg(mii_info); | ||
3932 | |||
3933 | /* Forcing failed! Give up */ | ||
3934 | if (result) { | ||
3935 | ugeth_err("%s: Forcing failed!", mii_info->dev->name); | ||
3936 | return; | ||
3937 | } | ||
3938 | } | ||
3939 | |||
3940 | /* Kill the timer so it can be restarted */ | ||
3941 | del_timer_sync(&ugeth->phy_info_timer); | ||
3942 | |||
3943 | /* Grab the PHY interrupt, if necessary/possible */ | ||
3944 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
3945 | if (request_irq(ugeth->ug_info->phy_interrupt, | ||
3946 | phy_interrupt, IRQF_SHARED, | ||
3947 | "phy_interrupt", mii_info->dev) < 0) { | ||
3948 | ugeth_err("%s: Can't get IRQ %d (PHY)", | ||
3949 | mii_info->dev->name, | ||
3950 | ugeth->ug_info->phy_interrupt); | ||
3951 | } else { | ||
3952 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
3953 | MII_INTERRUPT_ENABLED); | ||
3954 | return; | ||
3955 | } | ||
3956 | } | ||
3957 | |||
3958 | /* Start the timer again, this time in order to | ||
3959 | * handle a change in status */ | ||
3960 | init_timer(&ugeth->phy_info_timer); | ||
3961 | ugeth->phy_info_timer.function = &ugeth_phy_timer; | ||
3962 | ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; | ||
3963 | mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); | ||
3964 | } | ||
3965 | |||
3966 | /* Called when something needs to use the ethernet device */ | 3625 | /* Called when something needs to use the ethernet device */ |
3967 | /* Returns 0 for success. */ | 3626 | /* Returns 0 for success. */ |
3968 | static int ucc_geth_open(struct net_device *dev) | 3627 | static int ucc_geth_open(struct net_device *dev) |
@@ -3979,6 +3638,12 @@ static int ucc_geth_open(struct net_device *dev) | |||
3979 | return -EINVAL; | 3638 | return -EINVAL; |
3980 | } | 3639 | } |
3981 | 3640 | ||
3641 | err = ucc_struct_init(ugeth); | ||
3642 | if (err) { | ||
3643 | ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); | ||
3644 | return err; | ||
3645 | } | ||
3646 | |||
3982 | err = ucc_geth_startup(ugeth); | 3647 | err = ucc_geth_startup(ugeth); |
3983 | if (err) { | 3648 | if (err) { |
3984 | ugeth_err("%s: Cannot configure net device, aborting.", | 3649 | ugeth_err("%s: Cannot configure net device, aborting.", |
@@ -4006,9 +3671,12 @@ static int ucc_geth_open(struct net_device *dev) | |||
4006 | 3671 | ||
4007 | err = init_phy(dev); | 3672 | err = init_phy(dev); |
4008 | if (err) { | 3673 | if (err) { |
4009 | ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); | 3674 | ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); |
4010 | return err; | 3675 | return err; |
4011 | } | 3676 | } |
3677 | |||
3678 | phy_start(ugeth->phydev); | ||
3679 | |||
4012 | #ifndef CONFIG_UGETH_NAPI | 3680 | #ifndef CONFIG_UGETH_NAPI |
4013 | err = | 3681 | err = |
4014 | request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, | 3682 | request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, |
@@ -4021,14 +3689,6 @@ static int ucc_geth_open(struct net_device *dev) | |||
4021 | } | 3689 | } |
4022 | #endif /* CONFIG_UGETH_NAPI */ | 3690 | #endif /* CONFIG_UGETH_NAPI */ |
4023 | 3691 | ||
4024 | /* Set up the PHY change work queue */ | ||
4025 | INIT_WORK(&ugeth->tq, ugeth_phy_change); | ||
4026 | |||
4027 | init_timer(&ugeth->phy_info_timer); | ||
4028 | ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; | ||
4029 | ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; | ||
4030 | mod_timer(&ugeth->phy_info_timer, jiffies + HZ); | ||
4031 | |||
4032 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); | 3692 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); |
4033 | if (err) { | 3693 | if (err) { |
4034 | ugeth_err("%s: Cannot enable net device, aborting.", dev->name); | 3694 | ugeth_err("%s: Cannot enable net device, aborting.", dev->name); |
@@ -4050,11 +3710,8 @@ static int ucc_geth_close(struct net_device *dev) | |||
4050 | 3710 | ||
4051 | ucc_geth_stop(ugeth); | 3711 | ucc_geth_stop(ugeth); |
4052 | 3712 | ||
4053 | /* Shutdown the PHY */ | 3713 | phy_disconnect(ugeth->phydev); |
4054 | if (ugeth->mii_info->phyinfo->close) | 3714 | ugeth->phydev = NULL; |
4055 | ugeth->mii_info->phyinfo->close(ugeth->mii_info); | ||
4056 | |||
4057 | kfree(ugeth->mii_info); | ||
4058 | 3715 | ||
4059 | netif_stop_queue(dev); | 3716 | netif_stop_queue(dev); |
4060 | 3717 | ||
@@ -4063,20 +3720,53 @@ static int ucc_geth_close(struct net_device *dev) | |||
4063 | 3720 | ||
4064 | const struct ethtool_ops ucc_geth_ethtool_ops = { }; | 3721 | const struct ethtool_ops ucc_geth_ethtool_ops = { }; |
4065 | 3722 | ||
3723 | static phy_interface_t to_phy_interface(const char *interface_type) | ||
3724 | { | ||
3725 | if (strcasecmp(interface_type, "mii") == 0) | ||
3726 | return PHY_INTERFACE_MODE_MII; | ||
3727 | if (strcasecmp(interface_type, "gmii") == 0) | ||
3728 | return PHY_INTERFACE_MODE_GMII; | ||
3729 | if (strcasecmp(interface_type, "tbi") == 0) | ||
3730 | return PHY_INTERFACE_MODE_TBI; | ||
3731 | if (strcasecmp(interface_type, "rmii") == 0) | ||
3732 | return PHY_INTERFACE_MODE_RMII; | ||
3733 | if (strcasecmp(interface_type, "rgmii") == 0) | ||
3734 | return PHY_INTERFACE_MODE_RGMII; | ||
3735 | if (strcasecmp(interface_type, "rgmii-id") == 0) | ||
3736 | return PHY_INTERFACE_MODE_RGMII_ID; | ||
3737 | if (strcasecmp(interface_type, "rtbi") == 0) | ||
3738 | return PHY_INTERFACE_MODE_RTBI; | ||
3739 | |||
3740 | return PHY_INTERFACE_MODE_MII; | ||
3741 | } | ||
3742 | |||
4066 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) | 3743 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) |
4067 | { | 3744 | { |
4068 | struct device *device = &ofdev->dev; | 3745 | struct device *device = &ofdev->dev; |
4069 | struct device_node *np = ofdev->node; | 3746 | struct device_node *np = ofdev->node; |
3747 | struct device_node *mdio; | ||
4070 | struct net_device *dev = NULL; | 3748 | struct net_device *dev = NULL; |
4071 | struct ucc_geth_private *ugeth = NULL; | 3749 | struct ucc_geth_private *ugeth = NULL; |
4072 | struct ucc_geth_info *ug_info; | 3750 | struct ucc_geth_info *ug_info; |
4073 | struct resource res; | 3751 | struct resource res; |
4074 | struct device_node *phy; | 3752 | struct device_node *phy; |
4075 | int err, ucc_num, phy_interface; | 3753 | int err, ucc_num, max_speed = 0; |
4076 | static int mii_mng_configured = 0; | ||
4077 | const phandle *ph; | 3754 | const phandle *ph; |
4078 | const unsigned int *prop; | 3755 | const unsigned int *prop; |
4079 | const void *mac_addr; | 3756 | const void *mac_addr; |
3757 | phy_interface_t phy_interface; | ||
3758 | static const int enet_to_speed[] = { | ||
3759 | SPEED_10, SPEED_10, SPEED_10, | ||
3760 | SPEED_100, SPEED_100, SPEED_100, | ||
3761 | SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000, | ||
3762 | }; | ||
3763 | static const phy_interface_t enet_to_phy_interface[] = { | ||
3764 | PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII, | ||
3765 | PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII, | ||
3766 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, | ||
3767 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, | ||
3768 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, | ||
3769 | }; | ||
4080 | 3770 | ||
4081 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3771 | ugeth_vdbg("%s: IN", __FUNCTION__); |
4082 | 3772 | ||
@@ -4087,6 +3777,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4087 | 3777 | ||
4088 | ug_info = &ugeth_info[ucc_num]; | 3778 | ug_info = &ugeth_info[ucc_num]; |
4089 | ug_info->uf_info.ucc_num = ucc_num; | 3779 | ug_info->uf_info.ucc_num = ucc_num; |
3780 | |||
4090 | prop = get_property(np, "rx-clock", NULL); | 3781 | prop = get_property(np, "rx-clock", NULL); |
4091 | ug_info->uf_info.rx_clock = *prop; | 3782 | ug_info->uf_info.rx_clock = *prop; |
4092 | prop = get_property(np, "tx-clock", NULL); | 3783 | prop = get_property(np, "tx-clock", NULL); |
@@ -4104,13 +3795,72 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4104 | if (phy == NULL) | 3795 | if (phy == NULL) |
4105 | return -ENODEV; | 3796 | return -ENODEV; |
4106 | 3797 | ||
3798 | /* set the PHY address */ | ||
4107 | prop = get_property(phy, "reg", NULL); | 3799 | prop = get_property(phy, "reg", NULL); |
3800 | if (prop == NULL) | ||
3801 | return -1; | ||
4108 | ug_info->phy_address = *prop; | 3802 | ug_info->phy_address = *prop; |
4109 | prop = get_property(phy, "interface", NULL); | 3803 | |
4110 | ug_info->enet_interface = *prop; | 3804 | /* get the phy interface type, or default to MII */ |
4111 | ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0); | 3805 | prop = get_property(np, "interface-type", NULL); |
4112 | ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)? | 3806 | if (!prop) { |
4113 | 0:FSL_UGETH_BRD_HAS_PHY_INTR; | 3807 | /* handle interface property present in old trees */ |
3808 | prop = get_property(phy, "interface", NULL); | ||
3809 | if (prop != NULL) | ||
3810 | phy_interface = enet_to_phy_interface[*prop]; | ||
3811 | else | ||
3812 | phy_interface = PHY_INTERFACE_MODE_MII; | ||
3813 | } else { | ||
3814 | phy_interface = to_phy_interface((const char *)prop); | ||
3815 | } | ||
3816 | |||
3817 | /* get speed, or derive from interface */ | ||
3818 | prop = get_property(np, "max-speed", NULL); | ||
3819 | if (!prop) { | ||
3820 | /* handle interface property present in old trees */ | ||
3821 | prop = get_property(phy, "interface", NULL); | ||
3822 | if (prop != NULL) | ||
3823 | max_speed = enet_to_speed[*prop]; | ||
3824 | } else { | ||
3825 | max_speed = *prop; | ||
3826 | } | ||
3827 | if (!max_speed) { | ||
3828 | switch (phy_interface) { | ||
3829 | case PHY_INTERFACE_MODE_GMII: | ||
3830 | case PHY_INTERFACE_MODE_RGMII: | ||
3831 | case PHY_INTERFACE_MODE_RGMII_ID: | ||
3832 | case PHY_INTERFACE_MODE_TBI: | ||
3833 | case PHY_INTERFACE_MODE_RTBI: | ||
3834 | max_speed = SPEED_1000; | ||
3835 | break; | ||
3836 | default: | ||
3837 | max_speed = SPEED_100; | ||
3838 | break; | ||
3839 | } | ||
3840 | } | ||
3841 | |||
3842 | if (max_speed == SPEED_1000) { | ||
3843 | ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; | ||
3844 | ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; | ||
3845 | ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT; | ||
3846 | ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; | ||
3847 | ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; | ||
3848 | ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; | ||
3849 | } | ||
3850 | |||
3851 | /* Set the bus id */ | ||
3852 | mdio = of_get_parent(phy); | ||
3853 | |||
3854 | if (mdio == NULL) | ||
3855 | return -1; | ||
3856 | |||
3857 | err = of_address_to_resource(mdio, 0, &res); | ||
3858 | of_node_put(mdio); | ||
3859 | |||
3860 | if (err) | ||
3861 | return -1; | ||
3862 | |||
3863 | ug_info->mdio_bus = res.start; | ||
4114 | 3864 | ||
4115 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", | 3865 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", |
4116 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, | 3866 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, |
@@ -4122,43 +3872,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4122 | return -ENODEV; | 3872 | return -ENODEV; |
4123 | } | 3873 | } |
4124 | 3874 | ||
4125 | /* FIXME: Work around for early chip rev. */ | ||
4126 | /* There's a bug in initial chip rev(s) in the RGMII ac */ | ||
4127 | /* timing. */ | ||
4128 | /* The following compensates by writing to the reserved */ | ||
4129 | /* QE Port Output Hold Registers (CPOH1?). */ | ||
4130 | prop = get_property(phy, "interface", NULL); | ||
4131 | phy_interface = *prop; | ||
4132 | if ((phy_interface == ENET_1000_RGMII) || | ||
4133 | (phy_interface == ENET_100_RGMII) || | ||
4134 | (phy_interface == ENET_10_RGMII)) { | ||
4135 | struct device_node *soc; | ||
4136 | phys_addr_t immrbase = -1; | ||
4137 | u32 *tmp_reg; | ||
4138 | u32 tmp_val; | ||
4139 | |||
4140 | soc = of_find_node_by_type(NULL, "soc"); | ||
4141 | if (soc) { | ||
4142 | unsigned int size; | ||
4143 | const void *prop = get_property(soc, "reg", &size); | ||
4144 | immrbase = of_translate_address(soc, prop); | ||
4145 | of_node_put(soc); | ||
4146 | }; | ||
4147 | |||
4148 | tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4); | ||
4149 | tmp_val = in_be32(tmp_reg); | ||
4150 | if (ucc_num == 1) | ||
4151 | out_be32(tmp_reg, tmp_val | 0x00003000); | ||
4152 | else if (ucc_num == 2) | ||
4153 | out_be32(tmp_reg, tmp_val | 0x0c000000); | ||
4154 | iounmap(tmp_reg); | ||
4155 | } | ||
4156 | |||
4157 | if (!mii_mng_configured) { | ||
4158 | ucc_set_qe_mux_mii_mng(ucc_num); | ||
4159 | mii_mng_configured = 1; | ||
4160 | } | ||
4161 | |||
4162 | /* Create an ethernet device instance */ | 3875 | /* Create an ethernet device instance */ |
4163 | dev = alloc_etherdev(sizeof(*ugeth)); | 3876 | dev = alloc_etherdev(sizeof(*ugeth)); |
4164 | 3877 | ||
@@ -4192,6 +3905,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4192 | dev->set_multicast_list = ucc_geth_set_multi; | 3905 | dev->set_multicast_list = ucc_geth_set_multi; |
4193 | dev->ethtool_ops = &ucc_geth_ethtool_ops; | 3906 | dev->ethtool_ops = &ucc_geth_ethtool_ops; |
4194 | 3907 | ||
3908 | ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; | ||
3909 | ugeth->phy_interface = phy_interface; | ||
3910 | ugeth->max_speed = max_speed; | ||
3911 | |||
4195 | err = register_netdev(dev); | 3912 | err = register_netdev(dev); |
4196 | if (err) { | 3913 | if (err) { |
4197 | ugeth_err("%s: Cannot register net device, aborting.", | 3914 | ugeth_err("%s: Cannot register net device, aborting.", |
@@ -4200,13 +3917,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4200 | return err; | 3917 | return err; |
4201 | } | 3918 | } |
4202 | 3919 | ||
4203 | ugeth->ug_info = ug_info; | ||
4204 | ugeth->dev = dev; | ||
4205 | |||
4206 | mac_addr = of_get_mac_address(np); | 3920 | mac_addr = of_get_mac_address(np); |
4207 | if (mac_addr) | 3921 | if (mac_addr) |
4208 | memcpy(dev->dev_addr, mac_addr, 6); | 3922 | memcpy(dev->dev_addr, mac_addr, 6); |
4209 | 3923 | ||
3924 | ugeth->ug_info = ug_info; | ||
3925 | ugeth->dev = dev; | ||
3926 | |||
4210 | return 0; | 3927 | return 0; |
4211 | } | 3928 | } |
4212 | 3929 | ||
@@ -4242,19 +3959,30 @@ static struct of_platform_driver ucc_geth_driver = { | |||
4242 | 3959 | ||
4243 | static int __init ucc_geth_init(void) | 3960 | static int __init ucc_geth_init(void) |
4244 | { | 3961 | { |
4245 | int i; | 3962 | int i, ret; |
3963 | |||
3964 | ret = uec_mdio_init(); | ||
3965 | |||
3966 | if (ret) | ||
3967 | return ret; | ||
4246 | 3968 | ||
4247 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); | 3969 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); |
4248 | for (i = 0; i < 8; i++) | 3970 | for (i = 0; i < 8; i++) |
4249 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, | 3971 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, |
4250 | sizeof(ugeth_primary_info)); | 3972 | sizeof(ugeth_primary_info)); |
4251 | 3973 | ||
4252 | return of_register_platform_driver(&ucc_geth_driver); | 3974 | ret = of_register_platform_driver(&ucc_geth_driver); |
3975 | |||
3976 | if (ret) | ||
3977 | uec_mdio_exit(); | ||
3978 | |||
3979 | return ret; | ||
4253 | } | 3980 | } |
4254 | 3981 | ||
4255 | static void __exit ucc_geth_exit(void) | 3982 | static void __exit ucc_geth_exit(void) |
4256 | { | 3983 | { |
4257 | of_unregister_platform_driver(&ucc_geth_driver); | 3984 | of_unregister_platform_driver(&ucc_geth_driver); |
3985 | uec_mdio_exit(); | ||
4258 | } | 3986 | } |
4259 | 3987 | ||
4260 | module_init(ucc_geth_init); | 3988 | module_init(ucc_geth_init); |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index a66561253593..6e97c20b92aa 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <asm/ucc.h> | 28 | #include <asm/ucc.h> |
29 | #include <asm/ucc_fast.h> | 29 | #include <asm/ucc_fast.h> |
30 | 30 | ||
31 | #include "ucc_geth_mii.h" | ||
32 | |||
31 | #define NUM_TX_QUEUES 8 | 33 | #define NUM_TX_QUEUES 8 |
32 | #define NUM_RX_QUEUES 8 | 34 | #define NUM_RX_QUEUES 8 |
33 | #define NUM_BDS_IN_PREFETCHED_BDS 4 | 35 | #define NUM_BDS_IN_PREFETCHED_BDS 4 |
@@ -36,15 +38,6 @@ | |||
36 | #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 | 38 | #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 |
37 | #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 | 39 | #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 |
38 | 40 | ||
39 | struct ucc_mii_mng { | ||
40 | u32 miimcfg; /* MII management configuration reg */ | ||
41 | u32 miimcom; /* MII management command reg */ | ||
42 | u32 miimadd; /* MII management address reg */ | ||
43 | u32 miimcon; /* MII management control reg */ | ||
44 | u32 miimstat; /* MII management status reg */ | ||
45 | u32 miimind; /* MII management indication reg */ | ||
46 | } __attribute__ ((packed)); | ||
47 | |||
48 | struct ucc_geth { | 41 | struct ucc_geth { |
49 | struct ucc_fast uccf; | 42 | struct ucc_fast uccf; |
50 | 43 | ||
@@ -53,7 +46,7 @@ struct ucc_geth { | |||
53 | u32 ipgifg; /* interframe gap reg. */ | 46 | u32 ipgifg; /* interframe gap reg. */ |
54 | u32 hafdup; /* half-duplex reg. */ | 47 | u32 hafdup; /* half-duplex reg. */ |
55 | u8 res1[0x10]; | 48 | u8 res1[0x10]; |
56 | struct ucc_mii_mng miimng; /* MII management structure */ | 49 | u8 miimng[0x18]; /* MII management structure moved to _mii.h */ |
57 | u32 ifctl; /* interface control reg */ | 50 | u32 ifctl; /* interface control reg */ |
58 | u32 ifstat; /* interface statux reg */ | 51 | u32 ifstat; /* interface statux reg */ |
59 | u32 macstnaddr1; /* mac station address part 1 reg */ | 52 | u32 macstnaddr1; /* mac station address part 1 reg */ |
@@ -381,66 +374,6 @@ struct ucc_geth { | |||
381 | #define UCCS_MPD 0x01 /* Magic Packet | 374 | #define UCCS_MPD 0x01 /* Magic Packet |
382 | Detected */ | 375 | Detected */ |
383 | 376 | ||
384 | /* UCC GETH MIIMCFG (MII Management Configuration Register) */ | ||
385 | #define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset | ||
386 | management */ | ||
387 | #define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble | ||
388 | suppress */ | ||
389 | #define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide | ||
390 | << shift */ | ||
391 | #define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val | ||
392 | */ | ||
393 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */ | ||
394 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */ | ||
395 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */ | ||
396 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */ | ||
397 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10 | ||
398 | */ | ||
399 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14 | ||
400 | */ | ||
401 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16 | ||
402 | */ | ||
403 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20 | ||
404 | */ | ||
405 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28 | ||
406 | */ | ||
407 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32 | ||
408 | */ | ||
409 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48 | ||
410 | */ | ||
411 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64 | ||
412 | */ | ||
413 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80 | ||
414 | */ | ||
415 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by | ||
416 | 112 */ | ||
417 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by | ||
418 | 160 */ | ||
419 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by | ||
420 | 224 */ | ||
421 | |||
422 | /* UCC GETH MIIMCOM (MII Management Command Register) */ | ||
423 | #define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ | ||
424 | #define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ | ||
425 | |||
426 | /* UCC GETH MIIMADD (MII Management Address Register) */ | ||
427 | #define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address | ||
428 | << shift */ | ||
429 | #define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register | ||
430 | << shift */ | ||
431 | |||
432 | /* UCC GETH MIIMCON (MII Management Control Register) */ | ||
433 | #define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control | ||
434 | << shift */ | ||
435 | #define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status | ||
436 | << shift */ | ||
437 | |||
438 | /* UCC GETH MIIMIND (MII Management Indicator Register) */ | ||
439 | #define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ | ||
440 | #define MIIMIND_SCAN 0x00000002 /* Scan in | ||
441 | progress */ | ||
442 | #define MIIMIND_BUSY 0x00000001 | ||
443 | |||
444 | /* UCC GETH IFSTAT (Interface Status Register) */ | 377 | /* UCC GETH IFSTAT (Interface Status Register) */ |
445 | #define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive | 378 | #define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive |
446 | transmission | 379 | transmission |
@@ -1009,15 +942,6 @@ struct ucc_geth_hardware_statistics { | |||
1009 | register */ | 942 | register */ |
1010 | #define UCC_GETH_MACCFG1_INIT 0 | 943 | #define UCC_GETH_MACCFG1_INIT 0 |
1011 | #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) | 944 | #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) |
1012 | #define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \ | ||
1013 | (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) | ||
1014 | |||
1015 | /* Ethernet speed */ | ||
1016 | enum enet_speed { | ||
1017 | ENET_SPEED_10BT, /* 10 Base T */ | ||
1018 | ENET_SPEED_100BT, /* 100 Base T */ | ||
1019 | ENET_SPEED_1000BT /* 1000 Base T */ | ||
1020 | }; | ||
1021 | 945 | ||
1022 | /* Ethernet Address Type. */ | 946 | /* Ethernet Address Type. */ |
1023 | enum enet_addr_type { | 947 | enum enet_addr_type { |
@@ -1026,22 +950,6 @@ enum enet_addr_type { | |||
1026 | ENET_ADDR_TYPE_BROADCAST | 950 | ENET_ADDR_TYPE_BROADCAST |
1027 | }; | 951 | }; |
1028 | 952 | ||
1029 | /* TBI / MII Set Register */ | ||
1030 | enum enet_tbi_mii_reg { | ||
1031 | ENET_TBI_MII_CR = 0x00, /* Control (CR ) */ | ||
1032 | ENET_TBI_MII_SR = 0x01, /* Status (SR ) */ | ||
1033 | ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */ | ||
1034 | ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability | ||
1035 | (ANLPBPA) */ | ||
1036 | ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */ | ||
1037 | ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */ | ||
1038 | ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page | ||
1039 | (ANLPANP) */ | ||
1040 | ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */ | ||
1041 | ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */ | ||
1042 | ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */ | ||
1043 | }; | ||
1044 | |||
1045 | /* UCC GETH 82xx Ethernet Address Recognition Location */ | 953 | /* UCC GETH 82xx Ethernet Address Recognition Location */ |
1046 | enum ucc_geth_enet_address_recognition_location { | 954 | enum ucc_geth_enet_address_recognition_location { |
1047 | UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station | 955 | UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station |
@@ -1239,8 +1147,7 @@ struct ucc_geth_info { | |||
1239 | u16 pausePeriod; | 1147 | u16 pausePeriod; |
1240 | u16 extensionField; | 1148 | u16 extensionField; |
1241 | u8 phy_address; | 1149 | u8 phy_address; |
1242 | u32 board_flags; | 1150 | u32 mdio_bus; |
1243 | u32 phy_interrupt; | ||
1244 | u8 weightfactor[NUM_TX_QUEUES]; | 1151 | u8 weightfactor[NUM_TX_QUEUES]; |
1245 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; | 1152 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; |
1246 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; | 1153 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; |
@@ -1249,7 +1156,6 @@ struct ucc_geth_info { | |||
1249 | u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; | 1156 | u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; |
1250 | u16 bdRingLenTx[NUM_TX_QUEUES]; | 1157 | u16 bdRingLenTx[NUM_TX_QUEUES]; |
1251 | u16 bdRingLenRx[NUM_RX_QUEUES]; | 1158 | u16 bdRingLenRx[NUM_RX_QUEUES]; |
1252 | enum enet_interface enet_interface; | ||
1253 | enum ucc_geth_num_of_station_addresses numStationAddresses; | 1159 | enum ucc_geth_num_of_station_addresses numStationAddresses; |
1254 | enum qe_fltr_largest_external_tbl_lookup_key_size | 1160 | enum qe_fltr_largest_external_tbl_lookup_key_size |
1255 | largestexternallookupkeysize; | 1161 | largestexternallookupkeysize; |
@@ -1326,9 +1232,11 @@ struct ucc_geth_private { | |||
1326 | /* index of the first skb which hasn't been transmitted yet. */ | 1232 | /* index of the first skb which hasn't been transmitted yet. */ |
1327 | u16 skb_dirtytx[NUM_TX_QUEUES]; | 1233 | u16 skb_dirtytx[NUM_TX_QUEUES]; |
1328 | 1234 | ||
1329 | struct work_struct tq; | ||
1330 | struct timer_list phy_info_timer; | ||
1331 | struct ugeth_mii_info *mii_info; | 1235 | struct ugeth_mii_info *mii_info; |
1236 | struct phy_device *phydev; | ||
1237 | phy_interface_t phy_interface; | ||
1238 | int max_speed; | ||
1239 | uint32_t msg_enable; | ||
1332 | int oldspeed; | 1240 | int oldspeed; |
1333 | int oldduplex; | 1241 | int oldduplex; |
1334 | int oldlink; | 1242 | int oldlink; |
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c new file mode 100644 index 000000000000..73b5a538e8f4 --- /dev/null +++ b/drivers/net/ucc_geth_mii.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * drivers/net/ucc_geth_mii.c | ||
3 | * | ||
4 | * Gianfar Ethernet Driver -- MIIM bus implementation | ||
5 | * Provides Bus interface for MIIM regs | ||
6 | * | ||
7 | * Author: Li Yang | ||
8 | * | ||
9 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <asm/ocp.h> | ||
35 | #include <linux/crc32.h> | ||
36 | #include <linux/mii.h> | ||
37 | #include <linux/phy.h> | ||
38 | #include <linux/fsl_devices.h> | ||
39 | |||
40 | #include <asm/of_platform.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/uaccess.h> | ||
44 | #include <asm/ucc.h> | ||
45 | |||
46 | #include "ucc_geth_mii.h" | ||
47 | #include "ucc_geth.h" | ||
48 | |||
49 | #define DEBUG | ||
50 | #ifdef DEBUG | ||
51 | #define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg) | ||
52 | #else | ||
53 | #define vdbg(format, arg...) do {} while(0) | ||
54 | #endif | ||
55 | |||
56 | #define DRV_DESC "QE UCC Ethernet Controller MII Bus" | ||
57 | #define DRV_NAME "fsl-uec_mdio" | ||
58 | |||
59 | /* Write value to the PHY for this device to the register at regnum, */ | ||
60 | /* waiting until the write is done before it returns. All PHY */ | ||
61 | /* configuration has to be done through the master UEC MIIM regs */ | ||
62 | int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | ||
63 | { | ||
64 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
65 | |||
66 | /* Setting up the MII Mangement Address Register */ | ||
67 | out_be32(®s->miimadd, | ||
68 | (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); | ||
69 | |||
70 | /* Setting up the MII Mangement Control Register with the value */ | ||
71 | out_be32(®s->miimcon, value); | ||
72 | |||
73 | /* Wait till MII management write is complete */ | ||
74 | while ((in_be32(®s->miimind)) & MIIMIND_BUSY) | ||
75 | cpu_relax(); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* Reads from register regnum in the PHY for device dev, */ | ||
81 | /* returning the value. Clears miimcom first. All PHY */ | ||
82 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
83 | int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | ||
84 | { | ||
85 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
86 | u16 value; | ||
87 | |||
88 | /* Setting up the MII Mangement Address Register */ | ||
89 | out_be32(®s->miimadd, | ||
90 | (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); | ||
91 | |||
92 | /* Clear miimcom, perform an MII management read cycle */ | ||
93 | out_be32(®s->miimcom, 0); | ||
94 | out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); | ||
95 | |||
96 | /* Wait till MII management write is complete */ | ||
97 | while ((in_be32(®s->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID)) | ||
98 | cpu_relax(); | ||
99 | |||
100 | /* Read MII management status */ | ||
101 | value = in_be32(®s->miimstat); | ||
102 | |||
103 | return value; | ||
104 | } | ||
105 | |||
106 | /* Reset the MIIM registers, and wait for the bus to free */ | ||
107 | int uec_mdio_reset(struct mii_bus *bus) | ||
108 | { | ||
109 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
110 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
111 | |||
112 | spin_lock_bh(&bus->mdio_lock); | ||
113 | |||
114 | /* Reset the management interface */ | ||
115 | out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT); | ||
116 | |||
117 | /* Setup the MII Mgmt clock speed */ | ||
118 | out_be32(®s->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112); | ||
119 | |||
120 | /* Wait until the bus is free */ | ||
121 | while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) | ||
122 | cpu_relax(); | ||
123 | |||
124 | spin_unlock_bh(&bus->mdio_lock); | ||
125 | |||
126 | if (timeout <= 0) { | ||
127 | printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); | ||
128 | return -EBUSY; | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) | ||
135 | { | ||
136 | struct device *device = &ofdev->dev; | ||
137 | struct device_node *np = ofdev->node, *tempnp = NULL; | ||
138 | struct device_node *child = NULL; | ||
139 | struct ucc_mii_mng __iomem *regs; | ||
140 | struct mii_bus *new_bus; | ||
141 | struct resource res; | ||
142 | int k, err = 0; | ||
143 | |||
144 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | ||
145 | |||
146 | if (NULL == new_bus) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | new_bus->name = "UCC Ethernet Controller MII Bus"; | ||
150 | new_bus->read = &uec_mdio_read; | ||
151 | new_bus->write = &uec_mdio_write; | ||
152 | new_bus->reset = &uec_mdio_reset; | ||
153 | |||
154 | memset(&res, 0, sizeof(res)); | ||
155 | |||
156 | err = of_address_to_resource(np, 0, &res); | ||
157 | if (err) | ||
158 | goto reg_map_fail; | ||
159 | |||
160 | new_bus->id = res.start; | ||
161 | |||
162 | new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); | ||
163 | |||
164 | if (NULL == new_bus->irq) { | ||
165 | err = -ENOMEM; | ||
166 | goto reg_map_fail; | ||
167 | } | ||
168 | |||
169 | for (k = 0; k < 32; k++) | ||
170 | new_bus->irq[k] = PHY_POLL; | ||
171 | |||
172 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
173 | int irq = irq_of_parse_and_map(child, 0); | ||
174 | if (irq != NO_IRQ) { | ||
175 | const u32 *id = get_property(child, "reg", NULL); | ||
176 | new_bus->irq[*id] = irq; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* Set the base address */ | ||
181 | regs = ioremap(res.start, sizeof(struct ucc_mii_mng)); | ||
182 | |||
183 | if (NULL == regs) { | ||
184 | err = -ENOMEM; | ||
185 | goto ioremap_fail; | ||
186 | } | ||
187 | |||
188 | new_bus->priv = (void __force *)regs; | ||
189 | |||
190 | new_bus->dev = device; | ||
191 | dev_set_drvdata(device, new_bus); | ||
192 | |||
193 | /* Read MII management master from device tree */ | ||
194 | while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth")) | ||
195 | != NULL) { | ||
196 | struct resource tempres; | ||
197 | |||
198 | err = of_address_to_resource(tempnp, 0, &tempres); | ||
199 | if (err) | ||
200 | goto bus_register_fail; | ||
201 | |||
202 | /* if our mdio regs fall within this UCC regs range */ | ||
203 | if ((res.start >= tempres.start) && | ||
204 | (res.end <= tempres.end)) { | ||
205 | /* set this UCC to be the MII master */ | ||
206 | const u32 *id = get_property(tempnp, "device-id", NULL); | ||
207 | if (id == NULL) | ||
208 | goto bus_register_fail; | ||
209 | |||
210 | ucc_set_qe_mux_mii_mng(*id - 1); | ||
211 | |||
212 | /* assign the TBI an address which won't | ||
213 | * conflict with the PHYs */ | ||
214 | out_be32(®s->utbipar, UTBIPAR_INIT_TBIPA); | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | err = mdiobus_register(new_bus); | ||
220 | if (0 != err) { | ||
221 | printk(KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
222 | new_bus->name); | ||
223 | goto bus_register_fail; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | |||
228 | bus_register_fail: | ||
229 | iounmap(regs); | ||
230 | ioremap_fail: | ||
231 | kfree(new_bus->irq); | ||
232 | reg_map_fail: | ||
233 | kfree(new_bus); | ||
234 | |||
235 | return err; | ||
236 | } | ||
237 | |||
238 | int uec_mdio_remove(struct of_device *ofdev) | ||
239 | { | ||
240 | struct device *device = &ofdev->dev; | ||
241 | struct mii_bus *bus = dev_get_drvdata(device); | ||
242 | |||
243 | mdiobus_unregister(bus); | ||
244 | |||
245 | dev_set_drvdata(device, NULL); | ||
246 | |||
247 | iounmap((void __iomem *)bus->priv); | ||
248 | bus->priv = NULL; | ||
249 | kfree(bus); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static struct of_device_id uec_mdio_match[] = { | ||
255 | { | ||
256 | .type = "mdio", | ||
257 | .compatible = "ucc_geth_phy", | ||
258 | }, | ||
259 | {}, | ||
260 | }; | ||
261 | |||
262 | MODULE_DEVICE_TABLE(of, uec_mdio_match); | ||
263 | |||
264 | static struct of_platform_driver uec_mdio_driver = { | ||
265 | .name = DRV_NAME, | ||
266 | .probe = uec_mdio_probe, | ||
267 | .remove = uec_mdio_remove, | ||
268 | .match_table = uec_mdio_match, | ||
269 | }; | ||
270 | |||
271 | int __init uec_mdio_init(void) | ||
272 | { | ||
273 | return of_register_platform_driver(&uec_mdio_driver); | ||
274 | } | ||
275 | |||
276 | void __exit uec_mdio_exit(void) | ||
277 | { | ||
278 | of_unregister_platform_driver(&uec_mdio_driver); | ||
279 | } | ||
diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h new file mode 100644 index 000000000000..98430fe0bfc6 --- /dev/null +++ b/drivers/net/ucc_geth_mii.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * drivers/net/ucc_geth_mii.h | ||
3 | * | ||
4 | * Gianfar Ethernet Driver -- MII Management Bus Implementation | ||
5 | * Driver for the MDIO bus controller in the Gianfar register space | ||
6 | * | ||
7 | * Author: Andy Fleming | ||
8 | * Maintainer: Kumar Gala | ||
9 | * | ||
10 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | #ifndef __UEC_MII_H | ||
19 | #define __UEC_MII_H | ||
20 | |||
21 | /* UCC GETH MIIMCFG (MII Management Configuration Register) */ | ||
22 | #define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset | ||
23 | management */ | ||
24 | #define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble | ||
25 | suppress */ | ||
26 | #define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide | ||
27 | << shift */ | ||
28 | #define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */ | ||
29 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 | ||
30 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 | ||
31 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 | ||
32 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 | ||
33 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 | ||
34 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 | ||
35 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 | ||
36 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 | ||
37 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 | ||
38 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 | ||
39 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a | ||
40 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b | ||
41 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c | ||
42 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d | ||
43 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e | ||
44 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f | ||
45 | |||
46 | /* UCC GETH MIIMCOM (MII Management Command Register) */ | ||
47 | #define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ | ||
48 | #define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ | ||
49 | |||
50 | /* UCC GETH MIIMADD (MII Management Address Register) */ | ||
51 | #define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address | ||
52 | << shift */ | ||
53 | #define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register | ||
54 | << shift */ | ||
55 | |||
56 | /* UCC GETH MIIMCON (MII Management Control Register) */ | ||
57 | #define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control | ||
58 | << shift */ | ||
59 | #define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status | ||
60 | << shift */ | ||
61 | |||
62 | /* UCC GETH MIIMIND (MII Management Indicator Register) */ | ||
63 | #define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ | ||
64 | #define MIIMIND_SCAN 0x00000002 /* Scan in | ||
65 | progress */ | ||
66 | #define MIIMIND_BUSY 0x00000001 | ||
67 | |||
68 | /* Initial TBI Physical Address */ | ||
69 | #define UTBIPAR_INIT_TBIPA 0x1f | ||
70 | |||
71 | struct ucc_mii_mng { | ||
72 | u32 miimcfg; /* MII management configuration reg */ | ||
73 | u32 miimcom; /* MII management command reg */ | ||
74 | u32 miimadd; /* MII management address reg */ | ||
75 | u32 miimcon; /* MII management control reg */ | ||
76 | u32 miimstat; /* MII management status reg */ | ||
77 | u32 miimind; /* MII management indication reg */ | ||
78 | u8 notcare[28]; /* Space holder */ | ||
79 | u32 utbipar; /* TBI phy address reg */ | ||
80 | } __attribute__ ((packed)); | ||
81 | |||
82 | /* TBI / MII Set Register */ | ||
83 | enum enet_tbi_mii_reg { | ||
84 | ENET_TBI_MII_CR = 0x00, /* Control */ | ||
85 | ENET_TBI_MII_SR = 0x01, /* Status */ | ||
86 | ENET_TBI_MII_ANA = 0x04, /* AN advertisement */ | ||
87 | ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */ | ||
88 | ENET_TBI_MII_ANEX = 0x06, /* AN expansion */ | ||
89 | ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */ | ||
90 | ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */ | ||
91 | ENET_TBI_MII_EXST = 0x0F, /* Extended status */ | ||
92 | ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */ | ||
93 | ENET_TBI_MII_TBICON = 0x11 /* TBI control */ | ||
94 | }; | ||
95 | |||
96 | int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum); | ||
97 | int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | ||
98 | int __init uec_mdio_init(void); | ||
99 | void __exit uec_mdio_exit(void); | ||
100 | #endif /* __UEC_MII_H */ | ||
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c deleted file mode 100644 index 9373d895b9ec..000000000000 --- a/drivers/net/ucc_geth_phy.c +++ /dev/null | |||
@@ -1,785 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Author: Shlomi Gridish <gridish@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * UCC GETH Driver -- PHY handling | ||
8 | * | ||
9 | * Changelog: | ||
10 | * Jun 28, 2006 Li Yang <LeoLi@freescale.com> | ||
11 | * - Rearrange code and style fixes | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/version.h> | ||
34 | #include <linux/crc32.h> | ||
35 | #include <linux/mii.h> | ||
36 | #include <linux/ethtool.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "ucc_geth.h" | ||
43 | #include "ucc_geth_phy.h" | ||
44 | |||
45 | #define ugphy_printk(level, format, arg...) \ | ||
46 | printk(level format "\n", ## arg) | ||
47 | |||
48 | #define ugphy_dbg(format, arg...) \ | ||
49 | ugphy_printk(KERN_DEBUG, format , ## arg) | ||
50 | #define ugphy_err(format, arg...) \ | ||
51 | ugphy_printk(KERN_ERR, format , ## arg) | ||
52 | #define ugphy_info(format, arg...) \ | ||
53 | ugphy_printk(KERN_INFO, format , ## arg) | ||
54 | #define ugphy_warn(format, arg...) \ | ||
55 | ugphy_printk(KERN_WARNING, format , ## arg) | ||
56 | |||
57 | #ifdef UGETH_VERBOSE_DEBUG | ||
58 | #define ugphy_vdbg ugphy_dbg | ||
59 | #else | ||
60 | #define ugphy_vdbg(fmt, args...) do { } while (0) | ||
61 | #endif /* UGETH_VERBOSE_DEBUG */ | ||
62 | |||
63 | static void config_genmii_advert(struct ugeth_mii_info *mii_info); | ||
64 | static void genmii_setup_forced(struct ugeth_mii_info *mii_info); | ||
65 | static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); | ||
66 | static int gbit_config_aneg(struct ugeth_mii_info *mii_info); | ||
67 | static int genmii_config_aneg(struct ugeth_mii_info *mii_info); | ||
68 | static int genmii_update_link(struct ugeth_mii_info *mii_info); | ||
69 | static int genmii_read_status(struct ugeth_mii_info *mii_info); | ||
70 | |||
71 | static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum) | ||
72 | { | ||
73 | u16 retval; | ||
74 | unsigned long flags; | ||
75 | |||
76 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
77 | |||
78 | spin_lock_irqsave(&mii_info->mdio_lock, flags); | ||
79 | retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); | ||
80 | spin_unlock_irqrestore(&mii_info->mdio_lock, flags); | ||
81 | |||
82 | return retval; | ||
83 | } | ||
84 | |||
85 | static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) | ||
86 | { | ||
87 | unsigned long flags; | ||
88 | |||
89 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
90 | |||
91 | spin_lock_irqsave(&mii_info->mdio_lock, flags); | ||
92 | mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); | ||
93 | spin_unlock_irqrestore(&mii_info->mdio_lock, flags); | ||
94 | } | ||
95 | |||
96 | /* Write value to the PHY for this device to the register at regnum, */ | ||
97 | /* waiting until the write is done before it returns. All PHY */ | ||
98 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
99 | void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) | ||
100 | { | ||
101 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
102 | struct ucc_mii_mng *mii_regs; | ||
103 | enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; | ||
104 | u32 tmp_reg; | ||
105 | |||
106 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
107 | |||
108 | spin_lock_irq(&ugeth->lock); | ||
109 | |||
110 | mii_regs = ugeth->mii_info->mii_regs; | ||
111 | |||
112 | /* Set this UCC to be the master of the MII managment */ | ||
113 | ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); | ||
114 | |||
115 | /* Stop the MII management read cycle */ | ||
116 | out_be32(&mii_regs->miimcom, 0); | ||
117 | /* Setting up the MII Mangement Address Register */ | ||
118 | tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; | ||
119 | out_be32(&mii_regs->miimadd, tmp_reg); | ||
120 | |||
121 | /* Setting up the MII Mangement Control Register with the value */ | ||
122 | out_be32(&mii_regs->miimcon, (u32) value); | ||
123 | |||
124 | /* Wait till MII management write is complete */ | ||
125 | while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) | ||
126 | cpu_relax(); | ||
127 | |||
128 | spin_unlock_irq(&ugeth->lock); | ||
129 | |||
130 | udelay(10000); | ||
131 | } | ||
132 | |||
133 | /* Reads from register regnum in the PHY for device dev, */ | ||
134 | /* returning the value. Clears miimcom first. All PHY */ | ||
135 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
136 | int read_phy_reg(struct net_device *dev, int mii_id, int regnum) | ||
137 | { | ||
138 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
139 | struct ucc_mii_mng *mii_regs; | ||
140 | enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; | ||
141 | u32 tmp_reg; | ||
142 | u16 value; | ||
143 | |||
144 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
145 | |||
146 | spin_lock_irq(&ugeth->lock); | ||
147 | |||
148 | mii_regs = ugeth->mii_info->mii_regs; | ||
149 | |||
150 | /* Setting up the MII Mangement Address Register */ | ||
151 | tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; | ||
152 | out_be32(&mii_regs->miimadd, tmp_reg); | ||
153 | |||
154 | /* Perform an MII management read cycle */ | ||
155 | out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); | ||
156 | |||
157 | /* Wait till MII management write is complete */ | ||
158 | while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) | ||
159 | cpu_relax(); | ||
160 | |||
161 | udelay(10000); | ||
162 | |||
163 | /* Read MII management status */ | ||
164 | value = (u16) in_be32(&mii_regs->miimstat); | ||
165 | out_be32(&mii_regs->miimcom, 0); | ||
166 | if (value == 0xffff) | ||
167 | ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", | ||
168 | mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); | ||
169 | |||
170 | spin_unlock_irq(&ugeth->lock); | ||
171 | |||
172 | return (value); | ||
173 | } | ||
174 | |||
175 | void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) | ||
176 | { | ||
177 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
178 | |||
179 | if (mii_info->phyinfo->ack_interrupt) | ||
180 | mii_info->phyinfo->ack_interrupt(mii_info); | ||
181 | } | ||
182 | |||
183 | void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, | ||
184 | u32 interrupts) | ||
185 | { | ||
186 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
187 | |||
188 | mii_info->interrupts = interrupts; | ||
189 | if (mii_info->phyinfo->config_intr) | ||
190 | mii_info->phyinfo->config_intr(mii_info); | ||
191 | } | ||
192 | |||
193 | /* Writes MII_ADVERTISE with the appropriate values, after | ||
194 | * sanitizing advertise to make sure only supported features | ||
195 | * are advertised | ||
196 | */ | ||
197 | static void config_genmii_advert(struct ugeth_mii_info *mii_info) | ||
198 | { | ||
199 | u32 advertise; | ||
200 | u16 adv; | ||
201 | |||
202 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
203 | |||
204 | /* Only allow advertising what this PHY supports */ | ||
205 | mii_info->advertising &= mii_info->phyinfo->features; | ||
206 | advertise = mii_info->advertising; | ||
207 | |||
208 | /* Setup standard advertisement */ | ||
209 | adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE); | ||
210 | adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); | ||
211 | if (advertise & ADVERTISED_10baseT_Half) | ||
212 | adv |= ADVERTISE_10HALF; | ||
213 | if (advertise & ADVERTISED_10baseT_Full) | ||
214 | adv |= ADVERTISE_10FULL; | ||
215 | if (advertise & ADVERTISED_100baseT_Half) | ||
216 | adv |= ADVERTISE_100HALF; | ||
217 | if (advertise & ADVERTISED_100baseT_Full) | ||
218 | adv |= ADVERTISE_100FULL; | ||
219 | ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv); | ||
220 | } | ||
221 | |||
222 | static void genmii_setup_forced(struct ugeth_mii_info *mii_info) | ||
223 | { | ||
224 | u16 ctrl; | ||
225 | u32 features = mii_info->phyinfo->features; | ||
226 | |||
227 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
228 | |||
229 | ctrl = ucc_geth_phy_read(mii_info, MII_BMCR); | ||
230 | |||
231 | ctrl &= | ||
232 | ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); | ||
233 | ctrl |= BMCR_RESET; | ||
234 | |||
235 | switch (mii_info->speed) { | ||
236 | case SPEED_1000: | ||
237 | if (features & (SUPPORTED_1000baseT_Half | ||
238 | | SUPPORTED_1000baseT_Full)) { | ||
239 | ctrl |= BMCR_SPEED1000; | ||
240 | break; | ||
241 | } | ||
242 | mii_info->speed = SPEED_100; | ||
243 | case SPEED_100: | ||
244 | if (features & (SUPPORTED_100baseT_Half | ||
245 | | SUPPORTED_100baseT_Full)) { | ||
246 | ctrl |= BMCR_SPEED100; | ||
247 | break; | ||
248 | } | ||
249 | mii_info->speed = SPEED_10; | ||
250 | case SPEED_10: | ||
251 | if (features & (SUPPORTED_10baseT_Half | ||
252 | | SUPPORTED_10baseT_Full)) | ||
253 | break; | ||
254 | default: /* Unsupported speed! */ | ||
255 | ugphy_err("%s: Bad speed!", mii_info->dev->name); | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | ucc_geth_phy_write(mii_info, MII_BMCR, ctrl); | ||
260 | } | ||
261 | |||
262 | /* Enable and Restart Autonegotiation */ | ||
263 | static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) | ||
264 | { | ||
265 | u16 ctl; | ||
266 | |||
267 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
268 | |||
269 | ctl = ucc_geth_phy_read(mii_info, MII_BMCR); | ||
270 | ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
271 | ucc_geth_phy_write(mii_info, MII_BMCR, ctl); | ||
272 | } | ||
273 | |||
274 | static int gbit_config_aneg(struct ugeth_mii_info *mii_info) | ||
275 | { | ||
276 | u16 adv; | ||
277 | u32 advertise; | ||
278 | |||
279 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
280 | |||
281 | if (mii_info->autoneg) { | ||
282 | /* Configure the ADVERTISE register */ | ||
283 | config_genmii_advert(mii_info); | ||
284 | advertise = mii_info->advertising; | ||
285 | |||
286 | adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL); | ||
287 | adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | | ||
288 | MII_1000BASETCONTROL_HALFDUPLEXCAP); | ||
289 | if (advertise & SUPPORTED_1000baseT_Half) | ||
290 | adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; | ||
291 | if (advertise & SUPPORTED_1000baseT_Full) | ||
292 | adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; | ||
293 | ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv); | ||
294 | |||
295 | /* Start/Restart aneg */ | ||
296 | genmii_restart_aneg(mii_info); | ||
297 | } else | ||
298 | genmii_setup_forced(mii_info); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int genmii_config_aneg(struct ugeth_mii_info *mii_info) | ||
304 | { | ||
305 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
306 | |||
307 | if (mii_info->autoneg) { | ||
308 | config_genmii_advert(mii_info); | ||
309 | genmii_restart_aneg(mii_info); | ||
310 | } else | ||
311 | genmii_setup_forced(mii_info); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int genmii_update_link(struct ugeth_mii_info *mii_info) | ||
317 | { | ||
318 | u16 status; | ||
319 | |||
320 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
321 | |||
322 | /* Do a fake read */ | ||
323 | ucc_geth_phy_read(mii_info, MII_BMSR); | ||
324 | |||
325 | /* Read link and autonegotiation status */ | ||
326 | status = ucc_geth_phy_read(mii_info, MII_BMSR); | ||
327 | if ((status & BMSR_LSTATUS) == 0) | ||
328 | mii_info->link = 0; | ||
329 | else | ||
330 | mii_info->link = 1; | ||
331 | |||
332 | /* If we are autonegotiating, and not done, | ||
333 | * return an error */ | ||
334 | if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) | ||
335 | return -EAGAIN; | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int genmii_read_status(struct ugeth_mii_info *mii_info) | ||
341 | { | ||
342 | u16 status; | ||
343 | int err; | ||
344 | |||
345 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
346 | |||
347 | /* Update the link, but return if there | ||
348 | * was an error */ | ||
349 | err = genmii_update_link(mii_info); | ||
350 | if (err) | ||
351 | return err; | ||
352 | |||
353 | if (mii_info->autoneg) { | ||
354 | status = ucc_geth_phy_read(mii_info, MII_LPA); | ||
355 | |||
356 | if (status & (LPA_10FULL | LPA_100FULL)) | ||
357 | mii_info->duplex = DUPLEX_FULL; | ||
358 | else | ||
359 | mii_info->duplex = DUPLEX_HALF; | ||
360 | if (status & (LPA_100FULL | LPA_100HALF)) | ||
361 | mii_info->speed = SPEED_100; | ||
362 | else | ||
363 | mii_info->speed = SPEED_10; | ||
364 | mii_info->pause = 0; | ||
365 | } | ||
366 | /* On non-aneg, we assume what we put in BMCR is the speed, | ||
367 | * though magic-aneg shouldn't prevent this case from occurring | ||
368 | */ | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int marvell_init(struct ugeth_mii_info *mii_info) | ||
374 | { | ||
375 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
376 | |||
377 | ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); | ||
378 | ucc_geth_phy_write(mii_info, 0x1b, | ||
379 | (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); | ||
380 | ucc_geth_phy_write(mii_info, MII_BMCR, | ||
381 | ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); | ||
382 | msleep(4000); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int marvell_config_aneg(struct ugeth_mii_info *mii_info) | ||
388 | { | ||
389 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
390 | |||
391 | /* The Marvell PHY has an errata which requires | ||
392 | * that certain registers get written in order | ||
393 | * to restart autonegotiation */ | ||
394 | ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET); | ||
395 | |||
396 | ucc_geth_phy_write(mii_info, 0x1d, 0x1f); | ||
397 | ucc_geth_phy_write(mii_info, 0x1e, 0x200c); | ||
398 | ucc_geth_phy_write(mii_info, 0x1d, 0x5); | ||
399 | ucc_geth_phy_write(mii_info, 0x1e, 0); | ||
400 | ucc_geth_phy_write(mii_info, 0x1e, 0x100); | ||
401 | |||
402 | gbit_config_aneg(mii_info); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int marvell_read_status(struct ugeth_mii_info *mii_info) | ||
408 | { | ||
409 | u16 status; | ||
410 | int err; | ||
411 | |||
412 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
413 | |||
414 | /* Update the link, but return if there | ||
415 | * was an error */ | ||
416 | err = genmii_update_link(mii_info); | ||
417 | if (err) | ||
418 | return err; | ||
419 | |||
420 | /* If the link is up, read the speed and duplex */ | ||
421 | /* If we aren't autonegotiating, assume speeds | ||
422 | * are as set */ | ||
423 | if (mii_info->autoneg && mii_info->link) { | ||
424 | int speed; | ||
425 | status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); | ||
426 | |||
427 | /* Get the duplexity */ | ||
428 | if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) | ||
429 | mii_info->duplex = DUPLEX_FULL; | ||
430 | else | ||
431 | mii_info->duplex = DUPLEX_HALF; | ||
432 | |||
433 | /* Get the speed */ | ||
434 | speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; | ||
435 | switch (speed) { | ||
436 | case MII_M1011_PHY_SPEC_STATUS_1000: | ||
437 | mii_info->speed = SPEED_1000; | ||
438 | break; | ||
439 | case MII_M1011_PHY_SPEC_STATUS_100: | ||
440 | mii_info->speed = SPEED_100; | ||
441 | break; | ||
442 | default: | ||
443 | mii_info->speed = SPEED_10; | ||
444 | break; | ||
445 | } | ||
446 | mii_info->pause = 0; | ||
447 | } | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) | ||
453 | { | ||
454 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
455 | |||
456 | /* Clear the interrupts by reading the reg */ | ||
457 | ucc_geth_phy_read(mii_info, MII_M1011_IEVENT); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int marvell_config_intr(struct ugeth_mii_info *mii_info) | ||
463 | { | ||
464 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
465 | |||
466 | if (mii_info->interrupts == MII_INTERRUPT_ENABLED) | ||
467 | ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); | ||
468 | else | ||
469 | ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int cis820x_init(struct ugeth_mii_info *mii_info) | ||
475 | { | ||
476 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
477 | |||
478 | ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, | ||
479 | MII_CIS8201_AUXCONSTAT_INIT); | ||
480 | ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int cis820x_read_status(struct ugeth_mii_info *mii_info) | ||
486 | { | ||
487 | u16 status; | ||
488 | int err; | ||
489 | |||
490 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
491 | |||
492 | /* Update the link, but return if there | ||
493 | * was an error */ | ||
494 | err = genmii_update_link(mii_info); | ||
495 | if (err) | ||
496 | return err; | ||
497 | |||
498 | /* If the link is up, read the speed and duplex */ | ||
499 | /* If we aren't autonegotiating, assume speeds | ||
500 | * are as set */ | ||
501 | if (mii_info->autoneg && mii_info->link) { | ||
502 | int speed; | ||
503 | |||
504 | status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); | ||
505 | if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) | ||
506 | mii_info->duplex = DUPLEX_FULL; | ||
507 | else | ||
508 | mii_info->duplex = DUPLEX_HALF; | ||
509 | |||
510 | speed = status & MII_CIS8201_AUXCONSTAT_SPEED; | ||
511 | |||
512 | switch (speed) { | ||
513 | case MII_CIS8201_AUXCONSTAT_GBIT: | ||
514 | mii_info->speed = SPEED_1000; | ||
515 | break; | ||
516 | case MII_CIS8201_AUXCONSTAT_100: | ||
517 | mii_info->speed = SPEED_100; | ||
518 | break; | ||
519 | default: | ||
520 | mii_info->speed = SPEED_10; | ||
521 | break; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) | ||
529 | { | ||
530 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
531 | |||
532 | ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int cis820x_config_intr(struct ugeth_mii_info *mii_info) | ||
538 | { | ||
539 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
540 | |||
541 | if (mii_info->interrupts == MII_INTERRUPT_ENABLED) | ||
542 | ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); | ||
543 | else | ||
544 | ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | #define DM9161_DELAY 10 | ||
550 | |||
551 | static int dm9161_read_status(struct ugeth_mii_info *mii_info) | ||
552 | { | ||
553 | u16 status; | ||
554 | int err; | ||
555 | |||
556 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
557 | |||
558 | /* Update the link, but return if there | ||
559 | * was an error */ | ||
560 | err = genmii_update_link(mii_info); | ||
561 | if (err) | ||
562 | return err; | ||
563 | |||
564 | /* If the link is up, read the speed and duplex */ | ||
565 | /* If we aren't autonegotiating, assume speeds | ||
566 | * are as set */ | ||
567 | if (mii_info->autoneg && mii_info->link) { | ||
568 | status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR); | ||
569 | if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) | ||
570 | mii_info->speed = SPEED_100; | ||
571 | else | ||
572 | mii_info->speed = SPEED_10; | ||
573 | |||
574 | if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) | ||
575 | mii_info->duplex = DUPLEX_FULL; | ||
576 | else | ||
577 | mii_info->duplex = DUPLEX_HALF; | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int dm9161_config_aneg(struct ugeth_mii_info *mii_info) | ||
584 | { | ||
585 | struct dm9161_private *priv = mii_info->priv; | ||
586 | |||
587 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
588 | |||
589 | if (0 == priv->resetdone) | ||
590 | return -EAGAIN; | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static void dm9161_timer(unsigned long data) | ||
596 | { | ||
597 | struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; | ||
598 | struct dm9161_private *priv = mii_info->priv; | ||
599 | u16 status = ucc_geth_phy_read(mii_info, MII_BMSR); | ||
600 | |||
601 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
602 | |||
603 | if (status & BMSR_ANEGCOMPLETE) { | ||
604 | priv->resetdone = 1; | ||
605 | } else | ||
606 | mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); | ||
607 | } | ||
608 | |||
609 | static int dm9161_init(struct ugeth_mii_info *mii_info) | ||
610 | { | ||
611 | struct dm9161_private *priv; | ||
612 | |||
613 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
614 | |||
615 | /* Allocate the private data structure */ | ||
616 | priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); | ||
617 | |||
618 | if (NULL == priv) | ||
619 | return -ENOMEM; | ||
620 | |||
621 | mii_info->priv = priv; | ||
622 | |||
623 | /* Reset is not done yet */ | ||
624 | priv->resetdone = 0; | ||
625 | |||
626 | ucc_geth_phy_write(mii_info, MII_BMCR, | ||
627 | ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); | ||
628 | |||
629 | ucc_geth_phy_write(mii_info, MII_BMCR, | ||
630 | ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); | ||
631 | |||
632 | config_genmii_advert(mii_info); | ||
633 | /* Start/Restart aneg */ | ||
634 | genmii_config_aneg(mii_info); | ||
635 | |||
636 | /* Start a timer for DM9161_DELAY seconds to wait | ||
637 | * for the PHY to be ready */ | ||
638 | init_timer(&priv->timer); | ||
639 | priv->timer.function = &dm9161_timer; | ||
640 | priv->timer.data = (unsigned long)mii_info; | ||
641 | mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static void dm9161_close(struct ugeth_mii_info *mii_info) | ||
647 | { | ||
648 | struct dm9161_private *priv = mii_info->priv; | ||
649 | |||
650 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
651 | |||
652 | del_timer_sync(&priv->timer); | ||
653 | kfree(priv); | ||
654 | } | ||
655 | |||
656 | static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) | ||
657 | { | ||
658 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
659 | |||
660 | /* Clear the interrupts by reading the reg */ | ||
661 | ucc_geth_phy_read(mii_info, MII_DM9161_INTR); | ||
662 | |||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int dm9161_config_intr(struct ugeth_mii_info *mii_info) | ||
668 | { | ||
669 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
670 | |||
671 | if (mii_info->interrupts == MII_INTERRUPT_ENABLED) | ||
672 | ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); | ||
673 | else | ||
674 | ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /* Cicada 820x */ | ||
680 | static struct phy_info phy_info_cis820x = { | ||
681 | .phy_id = 0x000fc440, | ||
682 | .name = "Cicada Cis8204", | ||
683 | .phy_id_mask = 0x000fffc0, | ||
684 | .features = MII_GBIT_FEATURES, | ||
685 | .init = &cis820x_init, | ||
686 | .config_aneg = &gbit_config_aneg, | ||
687 | .read_status = &cis820x_read_status, | ||
688 | .ack_interrupt = &cis820x_ack_interrupt, | ||
689 | .config_intr = &cis820x_config_intr, | ||
690 | }; | ||
691 | |||
692 | static struct phy_info phy_info_dm9161 = { | ||
693 | .phy_id = 0x0181b880, | ||
694 | .phy_id_mask = 0x0ffffff0, | ||
695 | .name = "Davicom DM9161E", | ||
696 | .init = dm9161_init, | ||
697 | .config_aneg = dm9161_config_aneg, | ||
698 | .read_status = dm9161_read_status, | ||
699 | .close = dm9161_close, | ||
700 | }; | ||
701 | |||
702 | static struct phy_info phy_info_dm9161a = { | ||
703 | .phy_id = 0x0181b8a0, | ||
704 | .phy_id_mask = 0x0ffffff0, | ||
705 | .name = "Davicom DM9161A", | ||
706 | .features = MII_BASIC_FEATURES, | ||
707 | .init = dm9161_init, | ||
708 | .config_aneg = dm9161_config_aneg, | ||
709 | .read_status = dm9161_read_status, | ||
710 | .ack_interrupt = dm9161_ack_interrupt, | ||
711 | .config_intr = dm9161_config_intr, | ||
712 | .close = dm9161_close, | ||
713 | }; | ||
714 | |||
715 | static struct phy_info phy_info_marvell = { | ||
716 | .phy_id = 0x01410c00, | ||
717 | .phy_id_mask = 0xffffff00, | ||
718 | .name = "Marvell 88E11x1", | ||
719 | .features = MII_GBIT_FEATURES, | ||
720 | .init = &marvell_init, | ||
721 | .config_aneg = &marvell_config_aneg, | ||
722 | .read_status = &marvell_read_status, | ||
723 | .ack_interrupt = &marvell_ack_interrupt, | ||
724 | .config_intr = &marvell_config_intr, | ||
725 | }; | ||
726 | |||
727 | static struct phy_info phy_info_genmii = { | ||
728 | .phy_id = 0x00000000, | ||
729 | .phy_id_mask = 0x00000000, | ||
730 | .name = "Generic MII", | ||
731 | .features = MII_BASIC_FEATURES, | ||
732 | .config_aneg = genmii_config_aneg, | ||
733 | .read_status = genmii_read_status, | ||
734 | }; | ||
735 | |||
736 | static struct phy_info *phy_info[] = { | ||
737 | &phy_info_cis820x, | ||
738 | &phy_info_marvell, | ||
739 | &phy_info_dm9161, | ||
740 | &phy_info_dm9161a, | ||
741 | &phy_info_genmii, | ||
742 | NULL | ||
743 | }; | ||
744 | |||
745 | /* Use the PHY ID registers to determine what type of PHY is attached | ||
746 | * to device dev. return a struct phy_info structure describing that PHY | ||
747 | */ | ||
748 | struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) | ||
749 | { | ||
750 | u16 phy_reg; | ||
751 | u32 phy_ID; | ||
752 | int i; | ||
753 | struct phy_info *theInfo = NULL; | ||
754 | struct net_device *dev = mii_info->dev; | ||
755 | |||
756 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
757 | |||
758 | /* Grab the bits from PHYIR1, and put them in the upper half */ | ||
759 | phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1); | ||
760 | phy_ID = (phy_reg & 0xffff) << 16; | ||
761 | |||
762 | /* Grab the bits from PHYIR2, and put them in the lower half */ | ||
763 | phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2); | ||
764 | phy_ID |= (phy_reg & 0xffff); | ||
765 | |||
766 | /* loop through all the known PHY types, and find one that */ | ||
767 | /* matches the ID we read from the PHY. */ | ||
768 | for (i = 0; phy_info[i]; i++) | ||
769 | if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){ | ||
770 | theInfo = phy_info[i]; | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | /* This shouldn't happen, as we have generic PHY support */ | ||
775 | if (theInfo == NULL) { | ||
776 | ugphy_info("%s: PHY id %x is not supported!", dev->name, | ||
777 | phy_ID); | ||
778 | return NULL; | ||
779 | } else { | ||
780 | ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, | ||
781 | phy_ID); | ||
782 | } | ||
783 | |||
784 | return theInfo; | ||
785 | } | ||
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h deleted file mode 100644 index f5740783670f..000000000000 --- a/drivers/net/ucc_geth_phy.h +++ /dev/null | |||
@@ -1,217 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Author: Shlomi Gridish <gridish@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * UCC GETH Driver -- PHY handling | ||
8 | * | ||
9 | * Changelog: | ||
10 | * Jun 28, 2006 Li Yang <LeoLi@freescale.com> | ||
11 | * - Rearrange code and style fixes | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | */ | ||
19 | #ifndef __UCC_GETH_PHY_H__ | ||
20 | #define __UCC_GETH_PHY_H__ | ||
21 | |||
22 | #define MII_end ((u32)-2) | ||
23 | #define MII_read ((u32)-1) | ||
24 | |||
25 | #define MIIMIND_BUSY 0x00000001 | ||
26 | #define MIIMIND_NOTVALID 0x00000004 | ||
27 | |||
28 | #define UGETH_AN_TIMEOUT 2000 | ||
29 | |||
30 | /* 1000BT control (Marvell & BCM54xx at least) */ | ||
31 | #define MII_1000BASETCONTROL 0x09 | ||
32 | #define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 | ||
33 | #define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 | ||
34 | |||
35 | /* Cicada Extended Control Register 1 */ | ||
36 | #define MII_CIS8201_EXT_CON1 0x17 | ||
37 | #define MII_CIS8201_EXTCON1_INIT 0x0000 | ||
38 | |||
39 | /* Cicada Interrupt Mask Register */ | ||
40 | #define MII_CIS8201_IMASK 0x19 | ||
41 | #define MII_CIS8201_IMASK_IEN 0x8000 | ||
42 | #define MII_CIS8201_IMASK_SPEED 0x4000 | ||
43 | #define MII_CIS8201_IMASK_LINK 0x2000 | ||
44 | #define MII_CIS8201_IMASK_DUPLEX 0x1000 | ||
45 | #define MII_CIS8201_IMASK_MASK 0xf000 | ||
46 | |||
47 | /* Cicada Interrupt Status Register */ | ||
48 | #define MII_CIS8201_ISTAT 0x1a | ||
49 | #define MII_CIS8201_ISTAT_STATUS 0x8000 | ||
50 | #define MII_CIS8201_ISTAT_SPEED 0x4000 | ||
51 | #define MII_CIS8201_ISTAT_LINK 0x2000 | ||
52 | #define MII_CIS8201_ISTAT_DUPLEX 0x1000 | ||
53 | |||
54 | /* Cicada Auxiliary Control/Status Register */ | ||
55 | #define MII_CIS8201_AUX_CONSTAT 0x1c | ||
56 | #define MII_CIS8201_AUXCONSTAT_INIT 0x0004 | ||
57 | #define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 | ||
58 | #define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 | ||
59 | #define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 | ||
60 | #define MII_CIS8201_AUXCONSTAT_100 0x0008 | ||
61 | |||
62 | /* 88E1011 PHY Status Register */ | ||
63 | #define MII_M1011_PHY_SPEC_STATUS 0x11 | ||
64 | #define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 | ||
65 | #define MII_M1011_PHY_SPEC_STATUS_100 0x4000 | ||
66 | #define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 | ||
67 | #define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 | ||
68 | #define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 | ||
69 | #define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 | ||
70 | |||
71 | #define MII_M1011_IEVENT 0x13 | ||
72 | #define MII_M1011_IEVENT_CLEAR 0x0000 | ||
73 | |||
74 | #define MII_M1011_IMASK 0x12 | ||
75 | #define MII_M1011_IMASK_INIT 0x6400 | ||
76 | #define MII_M1011_IMASK_CLEAR 0x0000 | ||
77 | |||
78 | #define MII_DM9161_SCR 0x10 | ||
79 | #define MII_DM9161_SCR_INIT 0x0610 | ||
80 | |||
81 | /* DM9161 Specified Configuration and Status Register */ | ||
82 | #define MII_DM9161_SCSR 0x11 | ||
83 | #define MII_DM9161_SCSR_100F 0x8000 | ||
84 | #define MII_DM9161_SCSR_100H 0x4000 | ||
85 | #define MII_DM9161_SCSR_10F 0x2000 | ||
86 | #define MII_DM9161_SCSR_10H 0x1000 | ||
87 | |||
88 | /* DM9161 Interrupt Register */ | ||
89 | #define MII_DM9161_INTR 0x15 | ||
90 | #define MII_DM9161_INTR_PEND 0x8000 | ||
91 | #define MII_DM9161_INTR_DPLX_MASK 0x0800 | ||
92 | #define MII_DM9161_INTR_SPD_MASK 0x0400 | ||
93 | #define MII_DM9161_INTR_LINK_MASK 0x0200 | ||
94 | #define MII_DM9161_INTR_MASK 0x0100 | ||
95 | #define MII_DM9161_INTR_DPLX_CHANGE 0x0010 | ||
96 | #define MII_DM9161_INTR_SPD_CHANGE 0x0008 | ||
97 | #define MII_DM9161_INTR_LINK_CHANGE 0x0004 | ||
98 | #define MII_DM9161_INTR_INIT 0x0000 | ||
99 | #define MII_DM9161_INTR_STOP \ | ||
100 | (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ | ||
101 | | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) | ||
102 | |||
103 | /* DM9161 10BT Configuration/Status */ | ||
104 | #define MII_DM9161_10BTCSR 0x12 | ||
105 | #define MII_DM9161_10BTCSR_INIT 0x7800 | ||
106 | |||
107 | #define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ | ||
108 | SUPPORTED_10baseT_Full | \ | ||
109 | SUPPORTED_100baseT_Half | \ | ||
110 | SUPPORTED_100baseT_Full | \ | ||
111 | SUPPORTED_Autoneg | \ | ||
112 | SUPPORTED_TP | \ | ||
113 | SUPPORTED_MII) | ||
114 | |||
115 | #define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ | ||
116 | SUPPORTED_1000baseT_Half | \ | ||
117 | SUPPORTED_1000baseT_Full) | ||
118 | |||
119 | #define MII_READ_COMMAND 0x00000001 | ||
120 | |||
121 | #define MII_INTERRUPT_DISABLED 0x0 | ||
122 | #define MII_INTERRUPT_ENABLED 0x1 | ||
123 | /* Taken from mii_if_info and sungem_phy.h */ | ||
124 | struct ugeth_mii_info { | ||
125 | /* Information about the PHY type */ | ||
126 | /* And management functions */ | ||
127 | struct phy_info *phyinfo; | ||
128 | |||
129 | struct ucc_mii_mng *mii_regs; | ||
130 | |||
131 | /* forced speed & duplex (no autoneg) | ||
132 | * partner speed & duplex & pause (autoneg) | ||
133 | */ | ||
134 | int speed; | ||
135 | int duplex; | ||
136 | int pause; | ||
137 | |||
138 | /* The most recently read link state */ | ||
139 | int link; | ||
140 | |||
141 | /* Enabled Interrupts */ | ||
142 | u32 interrupts; | ||
143 | |||
144 | u32 advertising; | ||
145 | int autoneg; | ||
146 | int mii_id; | ||
147 | |||
148 | /* private data pointer */ | ||
149 | /* For use by PHYs to maintain extra state */ | ||
150 | void *priv; | ||
151 | |||
152 | /* Provided by host chip */ | ||
153 | struct net_device *dev; | ||
154 | |||
155 | /* A lock to ensure that only one thing can read/write | ||
156 | * the MDIO bus at a time */ | ||
157 | spinlock_t mdio_lock; | ||
158 | |||
159 | /* Provided by ethernet driver */ | ||
160 | int (*mdio_read) (struct net_device * dev, int mii_id, int reg); | ||
161 | void (*mdio_write) (struct net_device * dev, int mii_id, int reg, | ||
162 | int val); | ||
163 | }; | ||
164 | |||
165 | /* struct phy_info: a structure which defines attributes for a PHY | ||
166 | * | ||
167 | * id will contain a number which represents the PHY. During | ||
168 | * startup, the driver will poll the PHY to find out what its | ||
169 | * UID--as defined by registers 2 and 3--is. The 32-bit result | ||
170 | * gotten from the PHY will be ANDed with phy_id_mask to | ||
171 | * discard any bits which may change based on revision numbers | ||
172 | * unimportant to functionality | ||
173 | * | ||
174 | * There are 6 commands which take a ugeth_mii_info structure. | ||
175 | * Each PHY must declare config_aneg, and read_status. | ||
176 | */ | ||
177 | struct phy_info { | ||
178 | u32 phy_id; | ||
179 | char *name; | ||
180 | unsigned int phy_id_mask; | ||
181 | u32 features; | ||
182 | |||
183 | /* Called to initialize the PHY */ | ||
184 | int (*init) (struct ugeth_mii_info * mii_info); | ||
185 | |||
186 | /* Called to suspend the PHY for power */ | ||
187 | int (*suspend) (struct ugeth_mii_info * mii_info); | ||
188 | |||
189 | /* Reconfigures autonegotiation (or disables it) */ | ||
190 | int (*config_aneg) (struct ugeth_mii_info * mii_info); | ||
191 | |||
192 | /* Determines the negotiated speed and duplex */ | ||
193 | int (*read_status) (struct ugeth_mii_info * mii_info); | ||
194 | |||
195 | /* Clears any pending interrupts */ | ||
196 | int (*ack_interrupt) (struct ugeth_mii_info * mii_info); | ||
197 | |||
198 | /* Enables or disables interrupts */ | ||
199 | int (*config_intr) (struct ugeth_mii_info * mii_info); | ||
200 | |||
201 | /* Clears up any memory if needed */ | ||
202 | void (*close) (struct ugeth_mii_info * mii_info); | ||
203 | }; | ||
204 | |||
205 | struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info); | ||
206 | void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); | ||
207 | int read_phy_reg(struct net_device *dev, int mii_id, int regnum); | ||
208 | void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info); | ||
209 | void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, | ||
210 | u32 interrupts); | ||
211 | |||
212 | struct dm9161_private { | ||
213 | struct timer_list timer; | ||
214 | int resetdone; | ||
215 | }; | ||
216 | |||
217 | #endif /* __UCC_GETH_PHY_H__ */ | ||