diff options
author | Kim Phillips <kim.phillips@freescale.com> | 2007-04-13 01:26:03 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-04-28 11:01:04 -0400 |
commit | 728de4c927a3544b6d3da331b634035d4c75ca17 (patch) | |
tree | 5f05e0b318de9c1d517bd7bbca5964249c7cc885 /drivers/net | |
parent | a999589ccaae16472531e0616f23826ad097aa40 (diff) | |
download | linux-728de4c927a3544b6d3da331b634035d4c75ca17.tar.bz2 |
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/net')
-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 bool "Transmit on Demond support" depends on UCC_GETH -config UGETH_HAS_GIGA - bool - depends on UCC_GETH && PPC_MPC836x - config MV643XX_ETH tristate "MV-643XX Ethernet support" 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 \ gianfar_sysfs.o obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o -ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o +ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o # # 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 @@ #include <linux/fsl_devices.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/phy.h> #include <linux/workqueue.h> #include <asm/of_platform.h> @@ -41,7 +42,7 @@ #include <asm/ucc_fast.h> #include "ucc_geth.h" -#include "ucc_geth_phy.h" +#include "ucc_geth_mii.h" #undef DEBUG @@ -73,22 +74,13 @@ static struct ucc_geth_info ugeth_primary_info = { .bd_mem_part = MEM_PART_SYSTEM, .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, .max_rx_buf_length = 1536, -/* FIXME: should be changed in run time for 1G and 100M */ -#ifdef CONFIG_UGETH_HAS_GIGA - .urfs = UCC_GETH_URFS_GIGA_INIT, - .urfet = UCC_GETH_URFET_GIGA_INIT, - .urfset = UCC_GETH_URFSET_GIGA_INIT, - .utfs = UCC_GETH_UTFS_GIGA_INIT, - .utfet = UCC_GETH_UTFET_GIGA_INIT, - .utftt = UCC_GETH_UTFTT_GIGA_INIT, -#else + /* adjusted at startup if max-speed 1000 */ .urfs = UCC_GETH_URFS_INIT, .urfet = UCC_GETH_URFET_INIT, .urfset = UCC_GETH_URFSET_INIT, .utfs = UCC_GETH_UTFS_INIT, .utfet = UCC_GETH_UTFET_INIT, .utftt = UCC_GETH_UTFTT_INIT, -#endif .ufpt = 256, .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, @@ -217,70 +209,6 @@ static struct list_head *dequeue(struct list_head *lh) } } -static int get_interface_details(enum enet_interface enet_interface, - enum enet_speed *speed, - int *r10m, - int *rmm, - int *rpm, - int *tbi, int *limited_to_full_duplex) -{ - /* Analyze enet_interface according to Interface Mode - Configuration table */ - switch (enet_interface) { - case ENET_10_MII: - *speed = ENET_SPEED_10BT; - break; - case ENET_10_RMII: - *speed = ENET_SPEED_10BT; - *r10m = 1; - *rmm = 1; - break; - case ENET_10_RGMII: - *speed = ENET_SPEED_10BT; - *rpm = 1; - *r10m = 1; - *limited_to_full_duplex = 1; - break; - case ENET_100_MII: - *speed = ENET_SPEED_100BT; - break; - case ENET_100_RMII: - *speed = ENET_SPEED_100BT; - *rmm = 1; - break; - case ENET_100_RGMII: - *speed = ENET_SPEED_100BT; - *rpm = 1; - *limited_to_full_duplex = 1; - break; - case ENET_1000_GMII: - *speed = ENET_SPEED_1000BT; - *limited_to_full_duplex = 1; - break; - case ENET_1000_RGMII: - *speed = ENET_SPEED_1000BT; - *rpm = 1; - *limited_to_full_duplex = 1; - break; - case ENET_1000_TBI: - *speed = ENET_SPEED_1000BT; - *tbi = 1; - *limited_to_full_duplex = 1; - break; - case ENET_1000_RTBI: - *speed = ENET_SPEED_1000BT; - *rpm = 1; - *tbi = 1; - *limited_to_full_duplex = 1; - break; - default: - return -EINVAL; - break; - } - - return 0; -} - static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) { struct sk_buff *skb = NULL; @@ -758,24 +686,6 @@ static void dump_regs(struct ucc_geth_private *ugeth) ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", (u32) & ugeth->ug_regs->hafdup, in_be32(&ugeth->ug_regs->hafdup)); - ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", - (u32) & ugeth->ug_regs->miimng.miimcfg, - in_be32(&ugeth->ug_regs->miimng.miimcfg)); - ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", - (u32) & ugeth->ug_regs->miimng.miimcom, - in_be32(&ugeth->ug_regs->miimng.miimcom)); - ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", - (u32) & ugeth->ug_regs->miimng.miimadd, - in_be32(&ugeth->ug_regs->miimng.miimadd)); - ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", - (u32) & ugeth->ug_regs->miimng.miimcon, - in_be32(&ugeth->ug_regs->miimng.miimcon)); - ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", - (u32) & ugeth->ug_regs->miimng.miimstat, - in_be32(&ugeth->ug_regs->miimng.miimstat)); - ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", - (u32) & ugeth->ug_regs->miimng.miimind, - in_be32(&ugeth->ug_regs->miimng.miimind)); ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", (u32) & ugeth->ug_regs->ifctl, in_be32(&ugeth->ug_regs->ifctl)); @@ -1425,27 +1335,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0, return 0; } -static int init_mac_duplex_mode(int full_duplex, - int limited_to_full_duplex, - volatile u32 *maccfg2_register) -{ - u32 value = 0; - - /* some interfaces must work in full duplex mode */ - if ((full_duplex == 0) && (limited_to_full_duplex == 1)) - return -EINVAL; - - value = in_be32(maccfg2_register); - - if (full_duplex) - value |= MACCFG2_FDX; - else - value &= ~MACCFG2_FDX; - - out_be32(maccfg2_register, value); - return 0; -} - static int init_check_frame_length_mode(int length_check, volatile u32 *maccfg2_register) { @@ -1477,40 +1366,6 @@ static int init_preamble_length(u8 preamble_length, return 0; } -static int init_mii_management_configuration(int reset_mgmt, - int preamble_supress, - volatile u32 *miimcfg_register, - volatile u32 *miimind_register) -{ - unsigned int timeout = PHY_INIT_TIMEOUT; - u32 value = 0; - - value = in_be32(miimcfg_register); - if (reset_mgmt) { - value |= MIIMCFG_RESET_MANAGEMENT; - out_be32(miimcfg_register, value); - } - - value = 0; - - if (preamble_supress) - value |= MIIMCFG_NO_PREAMBLE; - - value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; - out_be32(miimcfg_register, value); - - /* Wait until the bus is free */ - while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) - cpu_relax(); - - if (timeout <= 0) { - ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); - return -ETIMEDOUT; - } - - return 0; -} - static int init_rx_parameters(int reject_broadcast, int receive_short_frames, int promiscuous, volatile u32 *upsmr_register) @@ -1570,10 +1425,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) struct ucc_geth_info *ug_info; struct ucc_geth *ug_regs; struct ucc_fast *uf_regs; - enum enet_speed speed; - int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = - 0, limited_to_full_duplex = 0; - u32 upsmr, maccfg2, utbipar, tbiBaseAddress; + int ret_val; + u32 upsmr, maccfg2, tbiBaseAddress; u16 value; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -1582,24 +1435,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) ug_regs = ugeth->ug_regs; uf_regs = ugeth->uccf->uf_regs; - /* Analyze enet_interface according to Interface Mode Configuration - table */ - ret_val = - get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, - &rpm, &tbi, &limited_to_full_duplex); - if (ret_val != 0) { - ugeth_err - ("%s: half duplex not supported in requested configuration.", - __FUNCTION__); - return ret_val; - } - /* Set MACCFG2 */ maccfg2 = in_be32(&ug_regs->maccfg2); maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; - if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) + if ((ugeth->max_speed == SPEED_10) || + (ugeth->max_speed == SPEED_100)) maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; - else if (speed == ENET_SPEED_1000BT) + else if (ugeth->max_speed == SPEED_1000) maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; maccfg2 |= ug_info->padAndCrc; out_be32(&ug_regs->maccfg2, maccfg2); @@ -1607,54 +1449,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) /* Set UPSMR */ upsmr = in_be32(&uf_regs->upsmr); upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); - if (rpm) + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { upsmr |= UPSMR_RPM; - if (r10m) - upsmr |= UPSMR_R10M; - if (tbi) + switch (ugeth->max_speed) { + case SPEED_10: + upsmr |= UPSMR_R10M; + /* FALLTHROUGH */ + case SPEED_100: + if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) + upsmr |= UPSMR_RMM; + } + } + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { upsmr |= UPSMR_TBIM; - if (rmm) - upsmr |= UPSMR_RMM; + } out_be32(&uf_regs->upsmr, upsmr); - /* Set UTBIPAR */ - utbipar = in_be32(&ug_regs->utbipar); - utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; - if (tbi) - utbipar |= - (ug_info->phy_address + - ugeth->ug_info->uf_info. - ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; - else - utbipar |= - (0x10 + - ugeth->ug_info->uf_info. - ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; - out_be32(&ug_regs->utbipar, utbipar); - /* Disable autonegotiation in tbi mode, because by default it comes up in autonegotiation mode. */ /* Note that this depends on proper setting in utbipar register. */ - if (tbi) { + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { tbiBaseAddress = in_be32(&ug_regs->utbipar); tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; - value = - ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, - ENET_TBI_MII_CR); + value = ugeth->phydev->bus->read(ugeth->phydev->bus, + (u8) tbiBaseAddress, ENET_TBI_MII_CR); value &= ~0x1000; /* Turn off autonegotiation */ - ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, - ENET_TBI_MII_CR, value); - } - - ret_val = init_mac_duplex_mode(1, - limited_to_full_duplex, - &ug_regs->maccfg2); - if (ret_val != 0) { - ugeth_err - ("%s: half duplex not supported in requested configuration.", - __FUNCTION__); - return ret_val; + ugeth->phydev->bus->write(ugeth->phydev->bus, + (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); } 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) * function converts those variables into the appropriate * register values, and can bring down the device if needed. */ + static void adjust_link(struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); struct ucc_geth *ug_regs; - u32 tempval; - struct ugeth_mii_info *mii_info = ugeth->mii_info; + struct ucc_fast *uf_regs; + struct phy_device *phydev = ugeth->phydev; + unsigned long flags; + int new_state = 0; ug_regs = ugeth->ug_regs; + uf_regs = ugeth->uccf->uf_regs; - if (mii_info->link) { + spin_lock_irqsave(&ugeth->lock, flags); + + if (phydev->link) { + u32 tempval = in_be32(&ug_regs->maccfg2); + u32 upsmr = in_be32(&uf_regs->upsmr); /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ - if (mii_info->duplex != ugeth->oldduplex) { - if (!(mii_info->duplex)) { - tempval = in_be32(&ug_regs->maccfg2); + if (phydev->duplex != ugeth->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) tempval &= ~(MACCFG2_FDX); - out_be32(&ug_regs->maccfg2, tempval); - - ugeth_info("%s: Half Duplex", dev->name); - } else { - tempval = in_be32(&ug_regs->maccfg2); + else tempval |= MACCFG2_FDX; - out_be32(&ug_regs->maccfg2, tempval); - - ugeth_info("%s: Full Duplex", dev->name); - } - - ugeth->oldduplex = mii_info->duplex; + ugeth->oldduplex = phydev->duplex; } - if (mii_info->speed != ugeth->oldspeed) { - switch (mii_info->speed) { - case 1000: - ugeth->ug_info->enet_interface = ENET_1000_RGMII; - break; - case 100: - ugeth->ug_info->enet_interface = ENET_100_RGMII; + if (phydev->speed != ugeth->oldspeed) { + new_state = 1; + switch (phydev->speed) { + case SPEED_1000: + tempval = ((tempval & + ~(MACCFG2_INTERFACE_MODE_MASK)) | + MACCFG2_INTERFACE_MODE_BYTE); break; - case 10: - ugeth->ug_info->enet_interface = ENET_10_RGMII; + case SPEED_100: + case SPEED_10: + tempval = ((tempval & + ~(MACCFG2_INTERFACE_MODE_MASK)) | + MACCFG2_INTERFACE_MODE_NIBBLE); + /* if reduced mode, re-set UPSMR.R10M */ + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || + (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { + if (phydev->speed == SPEED_10) + upsmr |= UPSMR_R10M; + else + upsmr &= ~(UPSMR_R10M); + } break; default: - ugeth_warn - ("%s: Ack! Speed (%d) is not 10/100/1000!", - dev->name, mii_info->speed); + if (netif_msg_link(ugeth)) + ugeth_warn( + "%s: Ack! Speed (%d) is not 10/100/1000!", + dev->name, phydev->speed); break; } - adjust_enet_interface(ugeth); - - ugeth_info("%s: Speed %dBT", dev->name, - mii_info->speed); - - ugeth->oldspeed = mii_info->speed; + ugeth->oldspeed = phydev->speed; } + out_be32(&ug_regs->maccfg2, tempval); + out_be32(&uf_regs->upsmr, upsmr); + if (!ugeth->oldlink) { - ugeth_info("%s: Link is up", dev->name); + new_state = 1; ugeth->oldlink = 1; - netif_carrier_on(dev); netif_schedule(dev); } - } else { - if (ugeth->oldlink) { - ugeth_info("%s: Link is down", dev->name); + } else if (ugeth->oldlink) { + new_state = 1; ugeth->oldlink = 0; ugeth->oldspeed = 0; ugeth->oldduplex = -1; - netif_carrier_off(dev); - } } + + if (new_state && netif_msg_link(ugeth)) + phy_print_status(phydev); + + spin_unlock_irqrestore(&ugeth->lock, flags); } /* Configure the PHY for dev. @@ -1753,94 +1592,40 @@ static void adjust_link(struct net_device *dev) */ static int init_phy(struct net_device *dev) { - struct ucc_geth_private *ugeth = netdev_priv(dev); - struct phy_info *curphy; - struct ucc_mii_mng *mii_regs; - struct ugeth_mii_info *mii_info; - int err; + struct ucc_geth_private *priv = netdev_priv(dev); + struct phy_device *phydev; + char phy_id[BUS_ID_SIZE]; - mii_regs = &ugeth->ug_regs->miimng; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; - ugeth->oldlink = 0; - ugeth->oldspeed = 0; - ugeth->oldduplex = -1; + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, + priv->ug_info->phy_address); - mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); + phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); - if (NULL == mii_info) { - ugeth_err("%s: Could not allocate mii_info", dev->name); - return -ENOMEM; + if (IS_ERR(phydev)) { + printk("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); } - mii_info->mii_regs = mii_regs; - mii_info->speed = SPEED_1000; - mii_info->duplex = DUPLEX_FULL; - mii_info->pause = 0; - mii_info->link = 0; - - mii_info->advertising = (ADVERTISED_10baseT_Half | + phydev->supported &= (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full); - mii_info->autoneg = 1; - - mii_info->mii_id = ugeth->ug_info->phy_address; - - mii_info->dev = dev; + ADVERTISED_100baseT_Full); - mii_info->mdio_read = &read_phy_reg; - mii_info->mdio_write = &write_phy_reg; + if (priv->max_speed == SPEED_1000) + phydev->supported |= ADVERTISED_1000baseT_Full; - spin_lock_init(&mii_info->mdio_lock); + phydev->advertising = phydev->supported; - ugeth->mii_info = mii_info; - - spin_lock_irq(&ugeth->lock); - - /* Set this UCC to be the master of the MII managment */ - ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); - - if (init_mii_management_configuration(1, - ugeth->ug_info-> - miiPreambleSupress, - &mii_regs->miimcfg, - &mii_regs->miimind)) { - ugeth_err("%s: The MII Bus is stuck!", dev->name); - err = -1; - goto bus_fail; - } - - spin_unlock_irq(&ugeth->lock); - - /* get info for this PHY */ - curphy = get_phy_info(ugeth->mii_info); - - if (curphy == NULL) { - ugeth_err("%s: No PHY found", dev->name); - err = -1; - goto no_phy; - } - - mii_info->phyinfo = curphy; - - /* Run the commands which initialize the PHY */ - if (curphy->init) { - err = curphy->init(ugeth->mii_info); - if (err) - goto phy_init_fail; - } + priv->phydev = phydev; return 0; - - phy_init_fail: - no_phy: - bus_fail: - kfree(mii_info); - - return err; } + #ifdef CONFIG_UGETH_TX_ON_DEMOND static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) { @@ -2487,6 +2272,7 @@ static void ucc_geth_set_multi(struct net_device *dev) static void ucc_geth_stop(struct ucc_geth_private *ugeth) { struct ucc_geth *ug_regs = ugeth->ug_regs; + struct phy_device *phydev = ugeth->phydev; u32 tempval; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -2495,8 +2281,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); /* Tell the kernel the link is down */ - ugeth->mii_info->link = 0; - adjust_link(ugeth->dev); + phy_stop(phydev); /* Mask all interrupts */ out_be32(ugeth->uccf->p_ucce, 0x00000000); @@ -2509,46 +2294,16 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); out_be32(&ug_regs->maccfg1, tempval); - if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { - /* Clear any pending interrupts */ - mii_clear_phy_interrupt(ugeth->mii_info); - - /* Disable PHY Interrupts */ - mii_configure_phy_interrupt(ugeth->mii_info, - MII_INTERRUPT_DISABLED); - } - free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); - if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { - free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); - } else { - del_timer_sync(&ugeth->phy_info_timer); - } - ucc_geth_memclean(ugeth); } -static int ucc_geth_startup(struct ucc_geth_private *ugeth) +static int ucc_struct_init(struct ucc_geth_private *ugeth) { - struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; - struct ucc_geth_init_pram *p_init_enet_pram; - struct ucc_fast_private *uccf; struct ucc_geth_info *ug_info; struct ucc_fast_info *uf_info; - struct ucc_fast *uf_regs; - struct ucc_geth *ug_regs; - int ret_val = -EINVAL; - u32 remoder = UCC_GETH_REMODER_INIT; - u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; - u32 ifstat, i, j, size, l2qt, l3qt, length; - u16 temoder = UCC_GETH_TEMODER_INIT; - u16 test; - u8 function_code = 0; - u8 *bd, *endOfRing; - u8 numThreadsRxNumerical, numThreadsTxNumerical; - - ugeth_vdbg("%s: IN", __FUNCTION__); + int i; ug_info = ugeth->ug_info; uf_info = &ug_info->uf_info; @@ -2647,12 +2402,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) for (i = 0; i < ug_info->numQueuesTx; i++) uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); /* Initialize the general fast UCC block. */ - if (ucc_fast_init(uf_info, &uccf)) { + if (ucc_fast_init(uf_info, &ugeth->uccf)) { ugeth_err("%s: Failed to init uccf.", __FUNCTION__); ucc_geth_memclean(ugeth); return -ENOMEM; } - ugeth->uccf = uccf; + + ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); + + return 0; +} + +static int ucc_geth_startup(struct ucc_geth_private *ugeth) +{ + struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; + struct ucc_geth_init_pram *p_init_enet_pram; + struct ucc_fast_private *uccf; + struct ucc_geth_info *ug_info; + struct ucc_fast_info *uf_info; + struct ucc_fast *uf_regs; + struct ucc_geth *ug_regs; + int ret_val = -EINVAL; + u32 remoder = UCC_GETH_REMODER_INIT; + u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; + u32 ifstat, i, j, size, l2qt, l3qt, length; + u16 temoder = UCC_GETH_TEMODER_INIT; + u16 test; + u8 function_code = 0; + u8 *bd, *endOfRing; + u8 numThreadsRxNumerical, numThreadsTxNumerical; + + ugeth_vdbg("%s: IN", __FUNCTION__); + uccf = ugeth->uccf; + ug_info = ugeth->ug_info; + uf_info = &ug_info->uf_info; + uf_regs = uccf->uf_regs; + ug_regs = ugeth->ug_regs; switch (ug_info->numThreadsRx) { case UCC_GETH_NUM_OF_THREADS_1: @@ -2711,10 +2496,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) || (ug_info->vlanOperationNonTagged != UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); - uf_regs = uccf->uf_regs; - ug_regs = (struct ucc_geth *) (uccf->uf_regs); - ugeth->ug_regs = ug_regs; - init_default_reg_vals(&uf_regs->upsmr, &ug_regs->maccfg1, &ug_regs->maccfg2); @@ -3841,128 +3622,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) return IRQ_HANDLED; } -static irqreturn_t phy_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct ucc_geth_private *ugeth = netdev_priv(dev); - - ugeth_vdbg("%s: IN", __FUNCTION__); - - /* Clear the interrupt */ - mii_clear_phy_interrupt(ugeth->mii_info); - - /* Disable PHY interrupts */ - mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); - - /* Schedule the phy change */ - schedule_work(&ugeth->tq); - - return IRQ_HANDLED; -} - -/* Scheduled by the phy_interrupt/timer to handle PHY changes */ -static void ugeth_phy_change(struct work_struct *work) -{ - struct ucc_geth_private *ugeth = - container_of(work, struct ucc_geth_private, tq); - struct net_device *dev = ugeth->dev; - struct ucc_geth *ug_regs; - int result = 0; - - ugeth_vdbg("%s: IN", __FUNCTION__); - - ug_regs = ugeth->ug_regs; - - /* Delay to give the PHY a chance to change the - * register state */ - msleep(1); - - /* Update the link, speed, duplex */ - result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); - - /* Adjust the known status as long as the link - * isn't still coming up */ - if ((0 == result) || (ugeth->mii_info->link == 0)) - adjust_link(dev); - - /* Reenable interrupts, if needed */ - if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) - mii_configure_phy_interrupt(ugeth->mii_info, - MII_INTERRUPT_ENABLED); -} - -/* Called every so often on systems that don't interrupt - * the core for PHY changes */ -static void ugeth_phy_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct ucc_geth_private *ugeth = netdev_priv(dev); - - schedule_work(&ugeth->tq); - - mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); -} - -/* Keep trying aneg for some time - * If, after GFAR_AN_TIMEOUT seconds, it has not - * finished, we switch to forced. - * Either way, once the process has completed, we either - * request the interrupt, or switch the timer over to - * using ugeth_phy_timer to check status */ -static void ugeth_phy_startup_timer(unsigned long data) -{ - struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; - struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev); - static int secondary = UGETH_AN_TIMEOUT; - int result; - - /* Configure the Auto-negotiation */ - result = mii_info->phyinfo->config_aneg(mii_info); - - /* If autonegotiation failed to start, and - * we haven't timed out, reset the timer, and return */ - if (result && secondary--) { - mod_timer(&ugeth->phy_info_timer, jiffies + HZ); - return; - } else if (result) { - /* Couldn't start autonegotiation. - * Try switching to forced */ - mii_info->autoneg = 0; - result = mii_info->phyinfo->config_aneg(mii_info); - - /* Forcing failed! Give up */ - if (result) { - ugeth_err("%s: Forcing failed!", mii_info->dev->name); - return; - } - } - - /* Kill the timer so it can be restarted */ - del_timer_sync(&ugeth->phy_info_timer); - - /* Grab the PHY interrupt, if necessary/possible */ - if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { - if (request_irq(ugeth->ug_info->phy_interrupt, - phy_interrupt, IRQF_SHARED, - "phy_interrupt", mii_info->dev) < 0) { - ugeth_err("%s: Can't get IRQ %d (PHY)", - mii_info->dev->name, - ugeth->ug_info->phy_interrupt); - } else { - mii_configure_phy_interrupt(ugeth->mii_info, - MII_INTERRUPT_ENABLED); - return; - } - } - - /* Start the timer again, this time in order to - * handle a change in status */ - init_timer(&ugeth->phy_info_timer); - ugeth->phy_info_timer.function = &ugeth_phy_timer; - ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; - mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); -} - /* Called when something needs to use the ethernet device */ /* Returns 0 for success. */ static int ucc_geth_open(struct net_device *dev) @@ -3979,6 +3638,12 @@ static int ucc_geth_open(struct net_device *dev) return -EINVAL; } + err = ucc_struct_init(ugeth); + if (err) { + ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); + return err; + } + err = ucc_geth_startup(ugeth); if (err) { ugeth_err("%s: Cannot configure net device, aborting.", @@ -4006,9 +3671,12 @@ static int ucc_geth_open(struct net_device *dev) err = init_phy(dev); if (err) { - ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); + ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); return err; } + + phy_start(ugeth->phydev); + #ifndef CONFIG_UGETH_NAPI err = 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) } #endif /* CONFIG_UGETH_NAPI */ - /* Set up the PHY change work queue */ - INIT_WORK(&ugeth->tq, ugeth_phy_change); - - init_timer(&ugeth->phy_info_timer); - ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; - ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; - mod_timer(&ugeth->phy_info_timer, jiffies + HZ); - err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); if (err) { ugeth_err("%s: Cannot enable net device, aborting.", dev->name); @@ -4050,11 +3710,8 @@ static int ucc_geth_close(struct net_device *dev) ucc_geth_stop(ugeth); - /* Shutdown the PHY */ - if (ugeth->mii_info->phyinfo->close) - ugeth->mii_info->phyinfo->close(ugeth->mii_info); - - kfree(ugeth->mii_info); + phy_disconnect(ugeth->phydev); + ugeth->phydev = NULL; netif_stop_queue(dev); @@ -4063,20 +3720,53 @@ static int ucc_geth_close(struct net_device *dev) const struct ethtool_ops ucc_geth_ethtool_ops = { }; +static phy_interface_t to_phy_interface(const char *interface_type) +{ + if (strcasecmp(interface_type, "mii") == 0) + return PHY_INTERFACE_MODE_MII; + if (strcasecmp(interface_type, "gmii") == 0) + return PHY_INTERFACE_MODE_GMII; + if (strcasecmp(interface_type, "tbi") == 0) + return PHY_INTERFACE_MODE_TBI; + if (strcasecmp(interface_type, "rmii") == 0) + return PHY_INTERFACE_MODE_RMII; + if (strcasecmp(interface_type, "rgmii") == 0) + return PHY_INTERFACE_MODE_RGMII; + if (strcasecmp(interface_type, "rgmii-id") == 0) + return PHY_INTERFACE_MODE_RGMII_ID; + if (strcasecmp(interface_type, "rtbi") == 0) + return PHY_INTERFACE_MODE_RTBI; + + return PHY_INTERFACE_MODE_MII; +} + static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) { struct device *device = &ofdev->dev; struct device_node *np = ofdev->node; + struct device_node *mdio; struct net_device *dev = NULL; struct ucc_geth_private *ugeth = NULL; struct ucc_geth_info *ug_info; struct resource res; struct device_node *phy; - int err, ucc_num, phy_interface; - static int mii_mng_configured = 0; + int err, ucc_num, max_speed = 0; const phandle *ph; const unsigned int *prop; const void *mac_addr; + phy_interface_t phy_interface; + static const int enet_to_speed[] = { + SPEED_10, SPEED_10, SPEED_10, + SPEED_100, SPEED_100, SPEED_100, + SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000, + }; + static const phy_interface_t enet_to_phy_interface[] = { + PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII, + PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII, + PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, + PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, + PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, + }; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -4087,6 +3777,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info = &ugeth_info[ucc_num]; ug_info->uf_info.ucc_num = ucc_num; + prop = get_property(np, "rx-clock", NULL); ug_info->uf_info.rx_clock = *prop; 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 if (phy == NULL) return -ENODEV; + /* set the PHY address */ prop = get_property(phy, "reg", NULL); + if (prop == NULL) + return -1; ug_info->phy_address = *prop; - prop = get_property(phy, "interface", NULL); - ug_info->enet_interface = *prop; - ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0); - ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)? - 0:FSL_UGETH_BRD_HAS_PHY_INTR; + + /* get the phy interface type, or default to MII */ + prop = get_property(np, "interface-type", NULL); + if (!prop) { + /* handle interface property present in old trees */ + prop = get_property(phy, "interface", NULL); + if (prop != NULL) + phy_interface = enet_to_phy_interface[*prop]; + else + phy_interface = PHY_INTERFACE_MODE_MII; + } else { + phy_interface = to_phy_interface((const char *)prop); + } + + /* get speed, or derive from interface */ + prop = get_property(np, "max-speed", NULL); + if (!prop) { + /* handle interface property present in old trees */ + prop = get_property(phy, "interface", NULL); + if (prop != NULL) + max_speed = enet_to_speed[*prop]; + } else { + max_speed = *prop; + } + if (!max_speed) { + switch (phy_interface) { + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_TBI: + case PHY_INTERFACE_MODE_RTBI: + max_speed = SPEED_1000; + break; + default: + max_speed = SPEED_100; + break; + } + } + + if (max_speed == SPEED_1000) { + ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; + ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; + ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT; + ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; + ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; + ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; + } + + /* Set the bus id */ + mdio = of_get_parent(phy); + + if (mdio == NULL) + return -1; + + err = of_address_to_resource(mdio, 0, &res); + of_node_put(mdio); + + if (err) + return -1; + + ug_info->mdio_bus = res.start; printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", 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 return -ENODEV; } - /* FIXME: Work around for early chip rev. */ - /* There's a bug in initial chip rev(s) in the RGMII ac */ - /* timing. */ - /* The following compensates by writing to the reserved */ - /* QE Port Output Hold Registers (CPOH1?). */ - prop = get_property(phy, "interface", NULL); - phy_interface = *prop; - if ((phy_interface == ENET_1000_RGMII) || - (phy_interface == ENET_100_RGMII) || - (phy_interface == ENET_10_RGMII)) { - struct device_node *soc; - phys_addr_t immrbase = -1; - u32 *tmp_reg; - u32 tmp_val; - - soc = of_find_node_by_type(NULL, "soc"); - if (soc) { - unsigned int size; - const void *prop = get_property(soc, "reg", &size); - immrbase = of_translate_address(soc, prop); - of_node_put(soc); - }; - - tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4); - tmp_val = in_be32(tmp_reg); - if (ucc_num == 1) - out_be32(tmp_reg, tmp_val | 0x00003000); - else if (ucc_num == 2) - out_be32(tmp_reg, tmp_val | 0x0c000000); - iounmap(tmp_reg); - } - - if (!mii_mng_configured) { - ucc_set_qe_mux_mii_mng(ucc_num); - mii_mng_configured = 1; - } - /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof(*ugeth)); @@ -4192,6 +3905,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->set_multicast_list = ucc_geth_set_multi; dev->ethtool_ops = &ucc_geth_ethtool_ops; + ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; + ugeth->phy_interface = phy_interface; + ugeth->max_speed = max_speed; + err = register_netdev(dev); if (err) { 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 return err; } - ugeth->ug_info = ug_info; - ugeth->dev = dev; - mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(dev->dev_addr, mac_addr, 6); + ugeth->ug_info = ug_info; + ugeth->dev = dev; + return 0; } @@ -4242,19 +3959,30 @@ static struct of_platform_driver ucc_geth_driver = { static int __init ucc_geth_init(void) { - int i; + int i, ret; + + ret = uec_mdio_init(); + + if (ret) + return ret; printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); for (i = 0; i < 8; i++) memcpy(&(ugeth_info[i]), &ugeth_primary_info, sizeof(ugeth_primary_info)); - return of_register_platform_driver(&ucc_geth_driver); + ret = of_register_platform_driver(&ucc_geth_driver); + + if (ret) + uec_mdio_exit(); + + return ret; } static void __exit ucc_geth_exit(void) { of_unregister_platform_driver(&ucc_geth_driver); + uec_mdio_exit(); } 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 @@ #include <asm/ucc.h> #include <asm/ucc_fast.h> +#include "ucc_geth_mii.h" + #define NUM_TX_QUEUES 8 #define NUM_RX_QUEUES 8 #define NUM_BDS_IN_PREFETCHED_BDS 4 @@ -36,15 +38,6 @@ #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 -struct ucc_mii_mng { - u32 miimcfg; /* MII management configuration reg */ - u32 miimcom; /* MII management command reg */ - u32 miimadd; /* MII management address reg */ - u32 miimcon; /* MII management control reg */ - u32 miimstat; /* MII management status reg */ - u32 miimind; /* MII management indication reg */ -} __attribute__ ((packed)); - struct ucc_geth { struct ucc_fast uccf; @@ -53,7 +46,7 @@ struct ucc_geth { u32 ipgifg; /* interframe gap reg. */ u32 hafdup; /* half-duplex reg. */ u8 res1[0x10]; - struct ucc_mii_mng miimng; /* MII management structure */ + u8 miimng[0x18]; /* MII management structure moved to _mii.h */ u32 ifctl; /* interface control reg */ u32 ifstat; /* interface statux reg */ u32 macstnaddr1; /* mac station address part 1 reg */ @@ -381,66 +374,6 @@ struct ucc_geth { #define UCCS_MPD 0x01 /* Magic Packet Detected */ -/* UCC GETH MIIMCFG (MII Management Configuration Register) */ -#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset - management */ -#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble - suppress */ -#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide - << shift */ -#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80 - */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by - 112 */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by - 160 */ -#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by - 224 */ - -/* UCC GETH MIIMCOM (MII Management Command Register) */ -#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ -#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ - -/* UCC GETH MIIMADD (MII Management Address Register) */ -#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address - << shift */ -#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register - << shift */ - -/* UCC GETH MIIMCON (MII Management Control Register) */ -#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control - << shift */ -#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status - << shift */ - -/* UCC GETH MIIMIND (MII Management Indicator Register) */ -#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ -#define MIIMIND_SCAN 0x00000002 /* Scan in - progress */ -#define MIIMIND_BUSY 0x00000001 - /* UCC GETH IFSTAT (Interface Status Register) */ #define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive transmission @@ -1009,15 +942,6 @@ struct ucc_geth_hardware_statistics { register */ #define UCC_GETH_MACCFG1_INIT 0 #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) -#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \ - (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) - -/* Ethernet speed */ -enum enet_speed { - ENET_SPEED_10BT, /* 10 Base T */ - ENET_SPEED_100BT, /* 100 Base T */ - ENET_SPEED_1000BT /* 1000 Base T */ -}; /* Ethernet Address Type. */ enum enet_addr_type { @@ -1026,22 +950,6 @@ enum enet_addr_type { ENET_ADDR_TYPE_BROADCAST }; -/* TBI / MII Set Register */ -enum enet_tbi_mii_reg { - ENET_TBI_MII_CR = 0x00, /* Control (CR ) */ - ENET_TBI_MII_SR = 0x01, /* Status (SR ) */ - ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */ - ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability - (ANLPBPA) */ - ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */ - ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */ - ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page - (ANLPANP) */ - ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */ - ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */ - ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */ -}; - /* UCC GETH 82xx Ethernet Address Recognition Location */ enum ucc_geth_enet_address_recognition_location { UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station @@ -1239,8 +1147,7 @@ struct ucc_geth_info { u16 pausePeriod; u16 extensionField; u8 phy_address; - u32 board_flags; - u32 phy_interrupt; + u32 mdio_bus; u8 weightfactor[NUM_TX_QUEUES]; u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; @@ -1249,7 +1156,6 @@ struct ucc_geth_info { u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; u16 bdRingLenTx[NUM_TX_QUEUES]; u16 bdRingLenRx[NUM_RX_QUEUES]; - enum enet_interface enet_interface; enum ucc_geth_num_of_station_addresses numStationAddresses; enum qe_fltr_largest_external_tbl_lookup_key_size largestexternallookupkeysize; @@ -1326,9 +1232,11 @@ struct ucc_geth_private { /* index of the first skb which hasn't been transmitted yet. */ u16 skb_dirtytx[NUM_TX_QUEUES]; - struct work_struct tq; - struct timer_list phy_info_timer; struct ugeth_mii_info *mii_info; + struct phy_device *phydev; + phy_interface_t phy_interface; + int max_speed; + uint32_t msg_enable; int oldspeed; int oldduplex; 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 @@ +/* + * drivers/net/ucc_geth_mii.c + * + * Gianfar Ethernet Driver -- MIIM bus implementation + * Provides Bus interface for MIIM regs + * + * Author: Li Yang + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <asm/ocp.h> +#include <linux/crc32.h> +#include <linux/mii.h> +#include <linux/phy.h> +#include <linux/fsl_devices.h> + +#include <asm/of_platform.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/ucc.h> + +#include "ucc_geth_mii.h" +#include "ucc_geth.h" + +#define DEBUG +#ifdef DEBUG +#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg) +#else +#define vdbg(format, arg...) do {} while(0) +#endif + +#define DRV_DESC "QE UCC Ethernet Controller MII Bus" +#define DRV_NAME "fsl-uec_mdio" + +/* Write value to the PHY for this device to the register at regnum, */ +/* waiting until the write is done before it returns. All PHY */ +/* configuration has to be done through the master UEC MIIM regs */ +int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) +{ + struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; + + /* Setting up the MII Mangement Address Register */ + out_be32(®s->miimadd, + (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); + + /* Setting up the MII Mangement Control Register with the value */ + out_be32(®s->miimcon, value); + + /* Wait till MII management write is complete */ + while ((in_be32(®s->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + return 0; +} + +/* Reads from register regnum in the PHY for device dev, */ +/* returning the value. Clears miimcom first. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; + u16 value; + + /* Setting up the MII Mangement Address Register */ + out_be32(®s->miimadd, + (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); + + /* Clear miimcom, perform an MII management read cycle */ + out_be32(®s->miimcom, 0); + out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); + + /* Wait till MII management write is complete */ + while ((in_be32(®s->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID)) + cpu_relax(); + + /* Read MII management status */ + value = in_be32(®s->miimstat); + + return value; +} + +/* Reset the MIIM registers, and wait for the bus to free */ +int uec_mdio_reset(struct mii_bus *bus) +{ + struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; + unsigned int timeout = PHY_INIT_TIMEOUT; + + spin_lock_bh(&bus->mdio_lock); + + /* Reset the management interface */ + out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT); + + /* Setup the MII Mgmt clock speed */ + out_be32(®s->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112); + + /* Wait until the bus is free */ + while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) + cpu_relax(); + + spin_unlock_bh(&bus->mdio_lock); + + if (timeout <= 0) { + printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); + return -EBUSY; + } + + return 0; +} + +static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) +{ + struct device *device = &ofdev->dev; + struct device_node *np = ofdev->node, *tempnp = NULL; + struct device_node *child = NULL; + struct ucc_mii_mng __iomem *regs; + struct mii_bus *new_bus; + struct resource res; + int k, err = 0; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + new_bus->name = "UCC Ethernet Controller MII Bus"; + new_bus->read = &uec_mdio_read; + new_bus->write = &uec_mdio_write; + new_bus->reset = &uec_mdio_reset; + + memset(&res, 0, sizeof(res)); + + err = of_address_to_resource(np, 0, &res); + if (err) + goto reg_map_fail; + + new_bus->id = res.start; + + new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); + + if (NULL == new_bus->irq) { + err = -ENOMEM; + goto reg_map_fail; + } + + for (k = 0; k < 32; k++) + new_bus->irq[k] = PHY_POLL; + + while ((child = of_get_next_child(np, child)) != NULL) { + int irq = irq_of_parse_and_map(child, 0); + if (irq != NO_IRQ) { + const u32 *id = get_property(child, "reg", NULL); + new_bus->irq[*id] = irq; + } + } + + /* Set the base address */ + regs = ioremap(res.start, sizeof(struct ucc_mii_mng)); + + if (NULL == regs) { + err = -ENOMEM; + goto ioremap_fail; + } + + new_bus->priv = (void __force *)regs; + + new_bus->dev = device; + dev_set_drvdata(device, new_bus); + + /* Read MII management master from device tree */ + while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth")) + != NULL) { + struct resource tempres; + + err = of_address_to_resource(tempnp, 0, &tempres); + if (err) + goto bus_register_fail; + + /* if our mdio regs fall within this UCC regs range */ + if ((res.start >= tempres.start) && + (res.end <= tempres.end)) { + /* set this UCC to be the MII master */ + const u32 *id = get_property(tempnp, "device-id", NULL); + if (id == NULL) + goto bus_register_fail; + + ucc_set_qe_mux_mii_mng(*id - 1); + + /* assign the TBI an address which won't + * conflict with the PHYs */ + out_be32(®s->utbipar, UTBIPAR_INIT_TBIPA); + break; + } + } + + err = mdiobus_register(new_bus); + if (0 != err) { + printk(KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + iounmap(regs); +ioremap_fail: + kfree(new_bus->irq); +reg_map_fail: + kfree(new_bus); + + return err; +} + +int uec_mdio_remove(struct of_device *ofdev) +{ + struct device *device = &ofdev->dev; + struct mii_bus *bus = dev_get_drvdata(device); + + mdiobus_unregister(bus); + + dev_set_drvdata(device, NULL); + + iounmap((void __iomem *)bus->priv); + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct of_device_id uec_mdio_match[] = { + { + .type = "mdio", + .compatible = "ucc_geth_phy", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, uec_mdio_match); + +static struct of_platform_driver uec_mdio_driver = { + .name = DRV_NAME, + .probe = uec_mdio_probe, + .remove = uec_mdio_remove, + .match_table = uec_mdio_match, +}; + +int __init uec_mdio_init(void) +{ + return of_register_platform_driver(&uec_mdio_driver); +} + +void __exit uec_mdio_exit(void) +{ + of_unregister_platform_driver(&uec_mdio_driver); +} 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 @@ +/* + * drivers/net/ucc_geth_mii.h + * + * Gianfar Ethernet Driver -- MII Management Bus Implementation + * Driver for the MDIO bus controller in the Gianfar register space + * + * Author: Andy Fleming + * Maintainer: Kumar Gala + * + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __UEC_MII_H +#define __UEC_MII_H + +/* UCC GETH MIIMCFG (MII Management Configuration Register) */ +#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset + management */ +#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble + suppress */ +#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide + << shift */ +#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f + +/* UCC GETH MIIMCOM (MII Management Command Register) */ +#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ +#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ + +/* UCC GETH MIIMADD (MII Management Address Register) */ +#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address + << shift */ +#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register + << shift */ + +/* UCC GETH MIIMCON (MII Management Control Register) */ +#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control + << shift */ +#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status + << shift */ + +/* UCC GETH MIIMIND (MII Management Indicator Register) */ +#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ +#define MIIMIND_SCAN 0x00000002 /* Scan in + progress */ +#define MIIMIND_BUSY 0x00000001 + +/* Initial TBI Physical Address */ +#define UTBIPAR_INIT_TBIPA 0x1f + +struct ucc_mii_mng { + u32 miimcfg; /* MII management configuration reg */ + u32 miimcom; /* MII management command reg */ + u32 miimadd; /* MII management address reg */ + u32 miimcon; /* MII management control reg */ + u32 miimstat; /* MII management status reg */ + u32 miimind; /* MII management indication reg */ + u8 notcare[28]; /* Space holder */ + u32 utbipar; /* TBI phy address reg */ +} __attribute__ ((packed)); + +/* TBI / MII Set Register */ +enum enet_tbi_mii_reg { + ENET_TBI_MII_CR = 0x00, /* Control */ + ENET_TBI_MII_SR = 0x01, /* Status */ + ENET_TBI_MII_ANA = 0x04, /* AN advertisement */ + ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */ + ENET_TBI_MII_ANEX = 0x06, /* AN expansion */ + ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */ + ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */ + ENET_TBI_MII_EXST = 0x0F, /* Extended status */ + ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */ + ENET_TBI_MII_TBICON = 0x11 /* TBI control */ +}; + +int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum); +int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); +int __init uec_mdio_init(void); +void __exit uec_mdio_exit(void); +#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 @@ -/* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. - * - * Author: Shlomi Gridish <gridish@freescale.com> - * - * Description: - * UCC GETH Driver -- PHY handling - * - * Changelog: - * Jun 28, 2006 Li Yang <LeoLi@freescale.com> - * - Rearrange code and style fixes - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/version.h> -#include <linux/crc32.h> -#include <linux/mii.h> -#include <linux/ethtool.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> - -#include "ucc_geth.h" -#include "ucc_geth_phy.h" - -#define ugphy_printk(level, format, arg...) \ - printk(level format "\n", ## arg) - -#define ugphy_dbg(format, arg...) \ - ugphy_printk(KERN_DEBUG, format , ## arg) -#define ugphy_err(format, arg...) \ - ugphy_printk(KERN_ERR, format , ## arg) -#define ugphy_info(format, arg...) \ - ugphy_printk(KERN_INFO, format , ## arg) -#define ugphy_warn(format, arg...) \ - ugphy_printk(KERN_WARNING, format , ## arg) - -#ifdef UGETH_VERBOSE_DEBUG -#define ugphy_vdbg ugphy_dbg -#else -#define ugphy_vdbg(fmt, args...) do { } while (0) -#endif /* UGETH_VERBOSE_DEBUG */ - -static void config_genmii_advert(struct ugeth_mii_info *mii_info); -static void genmii_setup_forced(struct ugeth_mii_info *mii_info); -static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); -static int gbit_config_aneg(struct ugeth_mii_info *mii_info); -static int genmii_config_aneg(struct ugeth_mii_info *mii_info); -static int genmii_update_link(struct ugeth_mii_info *mii_info); -static int genmii_read_status(struct ugeth_mii_info *mii_info); - -static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum) -{ - u16 retval; - unsigned long flags; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); - - return retval; -} - -static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) -{ - unsigned long flags; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - spin_lock_irqsave(&mii_info->mdio_lock, flags); - mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); -} - -/* Write value to the PHY for this device to the register at regnum, */ -/* waiting until the write is done before it returns. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) -{ - struct ucc_geth_private *ugeth = netdev_priv(dev); - struct ucc_mii_mng *mii_regs; - enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; - u32 tmp_reg; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - spin_lock_irq(&ugeth->lock); - - mii_regs = ugeth->mii_info->mii_regs; - - /* Set this UCC to be the master of the MII managment */ - ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); - - /* Stop the MII management read cycle */ - out_be32(&mii_regs->miimcom, 0); - /* Setting up the MII Mangement Address Register */ - tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; - out_be32(&mii_regs->miimadd, tmp_reg); - - /* Setting up the MII Mangement Control Register with the value */ - out_be32(&mii_regs->miimcon, (u32) value); - - /* Wait till MII management write is complete */ - while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) - cpu_relax(); - - spin_unlock_irq(&ugeth->lock); - - udelay(10000); -} - -/* Reads from register regnum in the PHY for device dev, */ -/* returning the value. Clears miimcom first. All PHY */ -/* configuration has to be done through the TSEC1 MIIM regs */ -int read_phy_reg(struct net_device *dev, int mii_id, int regnum) -{ - struct ucc_geth_private *ugeth = netdev_priv(dev); - struct ucc_mii_mng *mii_regs; - enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; - u32 tmp_reg; - u16 value; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - spin_lock_irq(&ugeth->lock); - - mii_regs = ugeth->mii_info->mii_regs; - - /* Setting up the MII Mangement Address Register */ - tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; - out_be32(&mii_regs->miimadd, tmp_reg); - - /* Perform an MII management read cycle */ - out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); - - /* Wait till MII management write is complete */ - while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) - cpu_relax(); - - udelay(10000); - - /* Read MII management status */ - value = (u16) in_be32(&mii_regs->miimstat); - out_be32(&mii_regs->miimcom, 0); - if (value == 0xffff) - ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", - mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); - - spin_unlock_irq(&ugeth->lock); - - return (value); -} - -void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (mii_info->phyinfo->ack_interrupt) - mii_info->phyinfo->ack_interrupt(mii_info); -} - -void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, - u32 interrupts) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - mii_info->interrupts = interrupts; - if (mii_info->phyinfo->config_intr) - mii_info->phyinfo->config_intr(mii_info); -} - -/* Writes MII_ADVERTISE with the appropriate values, after - * sanitizing advertise to make sure only supported features - * are advertised - */ -static void config_genmii_advert(struct ugeth_mii_info *mii_info) -{ - u32 advertise; - u16 adv; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Only allow advertising what this PHY supports */ - mii_info->advertising &= mii_info->phyinfo->features; - advertise = mii_info->advertising; - - /* Setup standard advertisement */ - adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); - if (advertise & ADVERTISED_10baseT_Half) - adv |= ADVERTISE_10HALF; - if (advertise & ADVERTISED_10baseT_Full) - adv |= ADVERTISE_10FULL; - if (advertise & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv); -} - -static void genmii_setup_forced(struct ugeth_mii_info *mii_info) -{ - u16 ctrl; - u32 features = mii_info->phyinfo->features; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - ctrl = ucc_geth_phy_read(mii_info, MII_BMCR); - - ctrl &= - ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); - ctrl |= BMCR_RESET; - - switch (mii_info->speed) { - case SPEED_1000: - if (features & (SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full)) { - ctrl |= BMCR_SPEED1000; - break; - } - mii_info->speed = SPEED_100; - case SPEED_100: - if (features & (SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full)) { - ctrl |= BMCR_SPEED100; - break; - } - mii_info->speed = SPEED_10; - case SPEED_10: - if (features & (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full)) - break; - default: /* Unsupported speed! */ - ugphy_err("%s: Bad speed!", mii_info->dev->name); - break; - } - - ucc_geth_phy_write(mii_info, MII_BMCR, ctrl); -} - -/* Enable and Restart Autonegotiation */ -static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) -{ - u16 ctl; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - ctl = ucc_geth_phy_read(mii_info, MII_BMCR); - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - ucc_geth_phy_write(mii_info, MII_BMCR, ctl); -} - -static int gbit_config_aneg(struct ugeth_mii_info *mii_info) -{ - u16 adv; - u32 advertise; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (mii_info->autoneg) { - /* Configure the ADVERTISE register */ - config_genmii_advert(mii_info); - advertise = mii_info->advertising; - - adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL); - adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | - MII_1000BASETCONTROL_HALFDUPLEXCAP); - if (advertise & SUPPORTED_1000baseT_Half) - adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; - if (advertise & SUPPORTED_1000baseT_Full) - adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; - ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv); - - /* Start/Restart aneg */ - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - -static int genmii_config_aneg(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (mii_info->autoneg) { - config_genmii_advert(mii_info); - genmii_restart_aneg(mii_info); - } else - genmii_setup_forced(mii_info); - - return 0; -} - -static int genmii_update_link(struct ugeth_mii_info *mii_info) -{ - u16 status; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Do a fake read */ - ucc_geth_phy_read(mii_info, MII_BMSR); - - /* Read link and autonegotiation status */ - status = ucc_geth_phy_read(mii_info, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) - mii_info->link = 0; - else - mii_info->link = 1; - - /* If we are autonegotiating, and not done, - * return an error */ - if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) - return -EAGAIN; - - return 0; -} - -static int genmii_read_status(struct ugeth_mii_info *mii_info) -{ - u16 status; - int err; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - if (mii_info->autoneg) { - status = ucc_geth_phy_read(mii_info, MII_LPA); - - if (status & (LPA_10FULL | LPA_100FULL)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - if (status & (LPA_100FULL | LPA_100HALF)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - mii_info->pause = 0; - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} - -static int marvell_init(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); - ucc_geth_phy_write(mii_info, 0x1b, - (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); - ucc_geth_phy_write(mii_info, MII_BMCR, - ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); - msleep(4000); - - return 0; -} - -static int marvell_config_aneg(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* The Marvell PHY has an errata which requires - * that certain registers get written in order - * to restart autonegotiation */ - ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET); - - ucc_geth_phy_write(mii_info, 0x1d, 0x1f); - ucc_geth_phy_write(mii_info, 0x1e, 0x200c); - ucc_geth_phy_write(mii_info, 0x1d, 0x5); - ucc_geth_phy_write(mii_info, 0x1e, 0); - ucc_geth_phy_write(mii_info, 0x1e, 0x100); - - gbit_config_aneg(mii_info); - - return 0; -} - -static int marvell_read_status(struct ugeth_mii_info *mii_info) -{ - u16 status; - int err; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); - - /* Get the duplexity */ - if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - /* Get the speed */ - speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; - switch (speed) { - case MII_M1011_PHY_SPEC_STATUS_1000: - mii_info->speed = SPEED_1000; - break; - case MII_M1011_PHY_SPEC_STATUS_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - mii_info->pause = 0; - } - - return 0; -} - -static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Clear the interrupts by reading the reg */ - ucc_geth_phy_read(mii_info, MII_M1011_IEVENT); - - return 0; -} - -static int marvell_config_intr(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); - else - ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); - - return 0; -} - -static int cis820x_init(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, - MII_CIS8201_AUXCONSTAT_INIT); - ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); - - return 0; -} - -static int cis820x_read_status(struct ugeth_mii_info *mii_info) -{ - u16 status; - int err; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - int speed; - - status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); - if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - - speed = status & MII_CIS8201_AUXCONSTAT_SPEED; - - switch (speed) { - case MII_CIS8201_AUXCONSTAT_GBIT: - mii_info->speed = SPEED_1000; - break; - case MII_CIS8201_AUXCONSTAT_100: - mii_info->speed = SPEED_100; - break; - default: - mii_info->speed = SPEED_10; - break; - } - } - - return 0; -} - -static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT); - - return 0; -} - -static int cis820x_config_intr(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); - else - ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0); - - return 0; -} - -#define DM9161_DELAY 10 - -static int dm9161_read_status(struct ugeth_mii_info *mii_info) -{ - u16 status; - int err; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Update the link, but return if there - * was an error */ - err = genmii_update_link(mii_info); - if (err) - return err; - - /* If the link is up, read the speed and duplex */ - /* If we aren't autonegotiating, assume speeds - * are as set */ - if (mii_info->autoneg && mii_info->link) { - status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR); - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; - - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - } - - return 0; -} - -static int dm9161_config_aneg(struct ugeth_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (0 == priv->resetdone) - return -EAGAIN; - - return 0; -} - -static void dm9161_timer(unsigned long data) -{ - struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; - struct dm9161_private *priv = mii_info->priv; - u16 status = ucc_geth_phy_read(mii_info, MII_BMSR); - - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (status & BMSR_ANEGCOMPLETE) { - priv->resetdone = 1; - } else - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); -} - -static int dm9161_init(struct ugeth_mii_info *mii_info) -{ - struct dm9161_private *priv; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Allocate the private data structure */ - priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); - - if (NULL == priv) - return -ENOMEM; - - mii_info->priv = priv; - - /* Reset is not done yet */ - priv->resetdone = 0; - - ucc_geth_phy_write(mii_info, MII_BMCR, - ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); - - ucc_geth_phy_write(mii_info, MII_BMCR, - ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); - - config_genmii_advert(mii_info); - /* Start/Restart aneg */ - genmii_config_aneg(mii_info); - - /* Start a timer for DM9161_DELAY seconds to wait - * for the PHY to be ready */ - init_timer(&priv->timer); - priv->timer.function = &dm9161_timer; - priv->timer.data = (unsigned long)mii_info; - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); - - return 0; -} - -static void dm9161_close(struct ugeth_mii_info *mii_info) -{ - struct dm9161_private *priv = mii_info->priv; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - del_timer_sync(&priv->timer); - kfree(priv); -} - -static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Clear the interrupts by reading the reg */ - ucc_geth_phy_read(mii_info, MII_DM9161_INTR); - - - return 0; -} - -static int dm9161_config_intr(struct ugeth_mii_info *mii_info) -{ - ugphy_vdbg("%s: IN", __FUNCTION__); - - if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); - else - ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); - - return 0; -} - -/* Cicada 820x */ -static struct phy_info phy_info_cis820x = { - .phy_id = 0x000fc440, - .name = "Cicada Cis8204", - .phy_id_mask = 0x000fffc0, - .features = MII_GBIT_FEATURES, - .init = &cis820x_init, - .config_aneg = &gbit_config_aneg, - .read_status = &cis820x_read_status, - .ack_interrupt = &cis820x_ack_interrupt, - .config_intr = &cis820x_config_intr, -}; - -static struct phy_info phy_info_dm9161 = { - .phy_id = 0x0181b880, - .phy_id_mask = 0x0ffffff0, - .name = "Davicom DM9161E", - .init = dm9161_init, - .config_aneg = dm9161_config_aneg, - .read_status = dm9161_read_status, - .close = dm9161_close, -}; - -static struct phy_info phy_info_dm9161a = { - .phy_id = 0x0181b8a0, - .phy_id_mask = 0x0ffffff0, - .name = "Davicom DM9161A", - .features = MII_BASIC_FEATURES, - .init = dm9161_init, - .config_aneg = dm9161_config_aneg, - .read_status = dm9161_read_status, - .ack_interrupt = dm9161_ack_interrupt, - .config_intr = dm9161_config_intr, - .close = dm9161_close, -}; - -static struct phy_info phy_info_marvell = { - .phy_id = 0x01410c00, - .phy_id_mask = 0xffffff00, - .name = "Marvell 88E11x1", - .features = MII_GBIT_FEATURES, - .init = &marvell_init, - .config_aneg = &marvell_config_aneg, - .read_status = &marvell_read_status, - .ack_interrupt = &marvell_ack_interrupt, - .config_intr = &marvell_config_intr, -}; - -static struct phy_info phy_info_genmii = { - .phy_id = 0x00000000, - .phy_id_mask = 0x00000000, - .name = "Generic MII", - .features = MII_BASIC_FEATURES, - .config_aneg = genmii_config_aneg, - .read_status = genmii_read_status, -}; - -static struct phy_info *phy_info[] = { - &phy_info_cis820x, - &phy_info_marvell, - &phy_info_dm9161, - &phy_info_dm9161a, - &phy_info_genmii, - NULL -}; - -/* Use the PHY ID registers to determine what type of PHY is attached - * to device dev. return a struct phy_info structure describing that PHY - */ -struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) -{ - u16 phy_reg; - u32 phy_ID; - int i; - struct phy_info *theInfo = NULL; - struct net_device *dev = mii_info->dev; - - ugphy_vdbg("%s: IN", __FUNCTION__); - - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1); - phy_ID = (phy_reg & 0xffff) << 16; - - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2); - phy_ID |= (phy_reg & 0xffff); - - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) - if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){ - theInfo = phy_info[i]; - break; - } - - /* This shouldn't happen, as we have generic PHY support */ - if (theInfo == NULL) { - ugphy_info("%s: PHY id %x is not supported!", dev->name, - phy_ID); - return NULL; - } else { - ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, - phy_ID); - } - - return theInfo; -} 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 @@ -/* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. - * - * Author: Shlomi Gridish <gridish@freescale.com> - * - * Description: - * UCC GETH Driver -- PHY handling - * - * Changelog: - * Jun 28, 2006 Li Yang <LeoLi@freescale.com> - * - Rearrange code and style fixes - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#ifndef __UCC_GETH_PHY_H__ -#define __UCC_GETH_PHY_H__ - -#define MII_end ((u32)-2) -#define MII_read ((u32)-1) - -#define MIIMIND_BUSY 0x00000001 -#define MIIMIND_NOTVALID 0x00000004 - -#define UGETH_AN_TIMEOUT 2000 - -/* 1000BT control (Marvell & BCM54xx at least) */ -#define MII_1000BASETCONTROL 0x09 -#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 -#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 - -/* Cicada Extended Control Register 1 */ -#define MII_CIS8201_EXT_CON1 0x17 -#define MII_CIS8201_EXTCON1_INIT 0x0000 - -/* Cicada Interrupt Mask Register */ -#define MII_CIS8201_IMASK 0x19 -#define MII_CIS8201_IMASK_IEN 0x8000 -#define MII_CIS8201_IMASK_SPEED 0x4000 -#define MII_CIS8201_IMASK_LINK 0x2000 -#define MII_CIS8201_IMASK_DUPLEX 0x1000 -#define MII_CIS8201_IMASK_MASK 0xf000 - -/* Cicada Interrupt Status Register */ -#define MII_CIS8201_ISTAT 0x1a -#define MII_CIS8201_ISTAT_STATUS 0x8000 -#define MII_CIS8201_ISTAT_SPEED 0x4000 -#define MII_CIS8201_ISTAT_LINK 0x2000 -#define MII_CIS8201_ISTAT_DUPLEX 0x1000 - -/* Cicada Auxiliary Control/Status Register */ -#define MII_CIS8201_AUX_CONSTAT 0x1c -#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 -#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 -#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 -#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 -#define MII_CIS8201_AUXCONSTAT_100 0x0008 - -/* 88E1011 PHY Status Register */ -#define MII_M1011_PHY_SPEC_STATUS 0x11 -#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 -#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 -#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 -#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 -#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 -#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 - -#define MII_M1011_IEVENT 0x13 -#define MII_M1011_IEVENT_CLEAR 0x0000 - -#define MII_M1011_IMASK 0x12 -#define MII_M1011_IMASK_INIT 0x6400 -#define MII_M1011_IMASK_CLEAR 0x0000 - -#define MII_DM9161_SCR 0x10 -#define MII_DM9161_SCR_INIT 0x0610 - -/* DM9161 Specified Configuration and Status Register */ -#define MII_DM9161_SCSR 0x11 -#define MII_DM9161_SCSR_100F 0x8000 -#define MII_DM9161_SCSR_100H 0x4000 -#define MII_DM9161_SCSR_10F 0x2000 -#define MII_DM9161_SCSR_10H 0x1000 - -/* DM9161 Interrupt Register */ -#define MII_DM9161_INTR 0x15 -#define MII_DM9161_INTR_PEND 0x8000 -#define MII_DM9161_INTR_DPLX_MASK 0x0800 -#define MII_DM9161_INTR_SPD_MASK 0x0400 -#define MII_DM9161_INTR_LINK_MASK 0x0200 -#define MII_DM9161_INTR_MASK 0x0100 -#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 -#define MII_DM9161_INTR_SPD_CHANGE 0x0008 -#define MII_DM9161_INTR_LINK_CHANGE 0x0004 -#define MII_DM9161_INTR_INIT 0x0000 -#define MII_DM9161_INTR_STOP \ -(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ - | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) - -/* DM9161 10BT Configuration/Status */ -#define MII_DM9161_10BTCSR 0x12 -#define MII_DM9161_10BTCSR_INIT 0x7800 - -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | \ - SUPPORTED_TP | \ - SUPPORTED_MII) - -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | \ - SUPPORTED_1000baseT_Full) - -#define MII_READ_COMMAND 0x00000001 - -#define MII_INTERRUPT_DISABLED 0x0 -#define MII_INTERRUPT_ENABLED 0x1 -/* Taken from mii_if_info and sungem_phy.h */ -struct ugeth_mii_info { - /* Information about the PHY type */ - /* And management functions */ - struct phy_info *phyinfo; - - struct ucc_mii_mng *mii_regs; - - /* forced speed & duplex (no autoneg) - * partner speed & duplex & pause (autoneg) - */ - int speed; - int duplex; - int pause; - - /* The most recently read link state */ - int link; - - /* Enabled Interrupts */ - u32 interrupts; - - u32 advertising; - int autoneg; - int mii_id; - - /* private data pointer */ - /* For use by PHYs to maintain extra state */ - void *priv; - - /* Provided by host chip */ - struct net_device *dev; - - /* A lock to ensure that only one thing can read/write - * the MDIO bus at a time */ - spinlock_t mdio_lock; - - /* Provided by ethernet driver */ - int (*mdio_read) (struct net_device * dev, int mii_id, int reg); - void (*mdio_write) (struct net_device * dev, int mii_id, int reg, - int val); -}; - -/* struct phy_info: a structure which defines attributes for a PHY - * - * id will contain a number which represents the PHY. During - * startup, the driver will poll the PHY to find out what its - * UID--as defined by registers 2 and 3--is. The 32-bit result - * gotten from the PHY will be ANDed with phy_id_mask to - * discard any bits which may change based on revision numbers - * unimportant to functionality - * - * There are 6 commands which take a ugeth_mii_info structure. - * Each PHY must declare config_aneg, and read_status. - */ -struct phy_info { - u32 phy_id; - char *name; - unsigned int phy_id_mask; - u32 features; - - /* Called to initialize the PHY */ - int (*init) (struct ugeth_mii_info * mii_info); - - /* Called to suspend the PHY for power */ - int (*suspend) (struct ugeth_mii_info * mii_info); - - /* Reconfigures autonegotiation (or disables it) */ - int (*config_aneg) (struct ugeth_mii_info * mii_info); - - /* Determines the negotiated speed and duplex */ - int (*read_status) (struct ugeth_mii_info * mii_info); - - /* Clears any pending interrupts */ - int (*ack_interrupt) (struct ugeth_mii_info * mii_info); - - /* Enables or disables interrupts */ - int (*config_intr) (struct ugeth_mii_info * mii_info); - - /* Clears up any memory if needed */ - void (*close) (struct ugeth_mii_info * mii_info); -}; - -struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info); -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); -int read_phy_reg(struct net_device *dev, int mii_id, int regnum); -void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info); -void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, - u32 interrupts); - -struct dm9161_private { - struct timer_list timer; - int resetdone; -}; - -#endif /* __UCC_GETH_PHY_H__ */ |