summaryrefslogtreecommitdiffstats
path: root/drivers/net/ucc_geth.c
diff options
context:
space:
mode:
authorKim Phillips <kim.phillips@freescale.com>2007-04-13 08:26:03 +0200
committerJeff Garzik <jeff@garzik.org>2007-04-28 17:01:04 +0200
commit728de4c927a3544b6d3da331b634035d4c75ca17 (patch)
tree5f05e0b318de9c1d517bd7bbca5964249c7cc885 /drivers/net/ucc_geth.c
parentphylib: add RGMII-ID interface mode definition (diff)
downloadlinux-728de4c927a3544b6d3da331b634035d4c75ca17.tar.xz
linux-728de4c927a3544b6d3da331b634035d4c75ca17.zip
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/ucc_geth.c')
-rw-r--r--drivers/net/ucc_geth.c814
1 files changed, 271 insertions, 543 deletions
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);