Commit 5b4b8454 authored by Vitaly Bordug's avatar Vitaly Bordug Committed by Jeff Garzik

[PATCH] FS_ENET: use PAL for mii management

This patch should update the fs_enet infrastructure to utilize Phy Abstraction
Layer subsystem.  Along with the above, there are apparent bugfixes, overhaul
and improvements.
Signed-off-by: default avatarVitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 11b0bacd
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
obj-$(CONFIG_FS_ENET) += fs_enet.o obj-$(CONFIG_FS_ENET) += fs_enet.o
obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o
obj-$(CONFIG_8260) += mac-fcc.o obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o
fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o fs_enet-objs := fs_enet-main.o
#ifndef FS_ENET_FEC_H
#define FS_ENET_FEC_H
/* CRC polynomium used by the FEC for the multicast group filtering */
#define FEC_CRC_POLY 0x04C11DB7
#define FEC_MAX_MULTICAST_ADDRS 64
/* Interrupt events/masks.
*/
#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */
#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */
#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */
#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */
#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */
#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */
#define FEC_ENET_RXF 0x02000000U /* Full frame received */
#define FEC_ENET_RXB 0x01000000U /* A buffer was received */
#define FEC_ENET_MII 0x00800000U /* MII interrupt */
#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */
#define FEC_ECNTRL_PINMUX 0x00000004
#define FEC_ECNTRL_ETHER_EN 0x00000002
#define FEC_ECNTRL_RESET 0x00000001
#define FEC_RCNTRL_BC_REJ 0x00000010
#define FEC_RCNTRL_PROM 0x00000008
#define FEC_RCNTRL_MII_MODE 0x00000004
#define FEC_RCNTRL_DRT 0x00000002
#define FEC_RCNTRL_LOOP 0x00000001
#define FEC_TCNTRL_FDEN 0x00000004
#define FEC_TCNTRL_HBC 0x00000002
#define FEC_TCNTRL_GTS 0x00000001
/*
* Delay to wait for FEC reset command to complete (in us)
*/
#define FEC_RESET_DELAY 50
#endif
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -682,35 +683,6 @@ static void fs_free_irq(struct net_device *dev, int irq) ...@@ -682,35 +683,6 @@ static void fs_free_irq(struct net_device *dev, int irq)
(*fep->ops->post_free_irq)(dev, irq); (*fep->ops->post_free_irq)(dev, irq);
} }
/**********************************************************************************/
/* This interrupt occurs when the PHY detects a link change. */
static irqreturn_t
fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct fs_enet_private *fep;
const struct fs_platform_info *fpi;
fep = netdev_priv(dev);
fpi = fep->fpi;
/*
* Acknowledge the interrupt if possible. If we have not
* found the PHY yet we can't process or acknowledge the
* interrupt now. Instead we ignore this interrupt for now,
* which we can do since it is edge triggered. It will be
* acknowledged later by fs_enet_open().
*/
if (!fep->phy)
return IRQ_NONE;
fs_mii_ack_int(dev);
fs_mii_link_status_change_check(dev, 0);
return IRQ_HANDLED;
}
static void fs_timeout(struct net_device *dev) static void fs_timeout(struct net_device *dev)
{ {
struct fs_enet_private *fep = netdev_priv(dev); struct fs_enet_private *fep = netdev_priv(dev);
...@@ -722,10 +694,13 @@ static void fs_timeout(struct net_device *dev) ...@@ -722,10 +694,13 @@ static void fs_timeout(struct net_device *dev)
spin_lock_irqsave(&fep->lock, flags); spin_lock_irqsave(&fep->lock, flags);
if (dev->flags & IFF_UP) { if (dev->flags & IFF_UP) {
phy_stop(fep->phydev);
(*fep->ops->stop)(dev); (*fep->ops->stop)(dev);
(*fep->ops->restart)(dev); (*fep->ops->restart)(dev);
phy_start(fep->phydev);
} }
phy_start(fep->phydev);
wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY);
spin_unlock_irqrestore(&fep->lock, flags); spin_unlock_irqrestore(&fep->lock, flags);
...@@ -733,35 +708,112 @@ static void fs_timeout(struct net_device *dev) ...@@ -733,35 +708,112 @@ static void fs_timeout(struct net_device *dev)
netif_wake_queue(dev); netif_wake_queue(dev);
} }
/*-----------------------------------------------------------------------------
* generic link-change handler - should be sufficient for most cases
*-----------------------------------------------------------------------------*/
static void generic_adjust_link(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
struct phy_device *phydev = fep->phydev;
int new_state = 0;
if (phydev->link) {
/* adjust to duplex mode */
if (phydev->duplex != fep->oldduplex){
new_state = 1;
fep->oldduplex = phydev->duplex;
}
if (phydev->speed != fep->oldspeed) {
new_state = 1;
fep->oldspeed = phydev->speed;
}
if (!fep->oldlink) {
new_state = 1;
fep->oldlink = 1;
netif_schedule(dev);
netif_carrier_on(dev);
netif_start_queue(dev);
}
if (new_state)
fep->ops->restart(dev);
} else if (fep->oldlink) {
new_state = 1;
fep->oldlink = 0;
fep->oldspeed = 0;
fep->oldduplex = -1;
netif_carrier_off(dev);
netif_stop_queue(dev);
}
if (new_state && netif_msg_link(fep))
phy_print_status(phydev);
}
static void fs_adjust_link(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&fep->lock, flags);
if(fep->ops->adjust_link)
fep->ops->adjust_link(dev);
else
generic_adjust_link(dev);
spin_unlock_irqrestore(&fep->lock, flags);
}
static int fs_init_phy(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
struct phy_device *phydev;
fep->oldlink = 0;
fep->oldspeed = 0;
fep->oldduplex = -1;
if(fep->fpi->bus_id)
phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0);
else {
printk("No phy bus ID specified in BSP code\n");
return -EINVAL;
}
if (IS_ERR(phydev)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
return PTR_ERR(phydev);
}
fep->phydev = phydev;
return 0;
}
static int fs_enet_open(struct net_device *dev) static int fs_enet_open(struct net_device *dev)
{ {
struct fs_enet_private *fep = netdev_priv(dev); struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
int r; int r;
int err;
/* Install our interrupt handler. */ /* Install our interrupt handler. */
r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
if (r != 0) { if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate FEC IRQ!", dev->name); ": %s Could not allocate FS_ENET IRQ!", dev->name);
return -EINVAL; return -EINVAL;
} }
/* Install our phy interrupt handler */ err = fs_init_phy(dev);
if (fpi->phy_irq != -1) { if(err)
return err;
r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt);
if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate PHY IRQ!", dev->name);
fs_free_irq(dev, fep->interrupt);
return -EINVAL;
}
}
fs_mii_startup(dev); phy_start(fep->phydev);
netif_carrier_off(dev);
fs_mii_link_status_change_check(dev, 1);
return 0; return 0;
} }
...@@ -769,20 +821,19 @@ static int fs_enet_open(struct net_device *dev) ...@@ -769,20 +821,19 @@ static int fs_enet_open(struct net_device *dev)
static int fs_enet_close(struct net_device *dev) static int fs_enet_close(struct net_device *dev)
{ {
struct fs_enet_private *fep = netdev_priv(dev); struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
unsigned long flags; unsigned long flags;
netif_stop_queue(dev); netif_stop_queue(dev);
netif_carrier_off(dev); netif_carrier_off(dev);
fs_mii_shutdown(dev); phy_stop(fep->phydev);
spin_lock_irqsave(&fep->lock, flags); spin_lock_irqsave(&fep->lock, flags);
(*fep->ops->stop)(dev); (*fep->ops->stop)(dev);
spin_unlock_irqrestore(&fep->lock, flags); spin_unlock_irqrestore(&fep->lock, flags);
/* release any irqs */ /* release any irqs */
if (fpi->phy_irq != -1) phy_disconnect(fep->phydev);
fs_free_irq(dev, fpi->phy_irq); fep->phydev = NULL;
fs_free_irq(dev, fep->interrupt); fs_free_irq(dev, fep->interrupt);
return 0; return 0;
...@@ -830,33 +881,19 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, ...@@ -830,33 +881,19 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct fs_enet_private *fep = netdev_priv(dev); struct fs_enet_private *fep = netdev_priv(dev);
unsigned long flags; return phy_ethtool_gset(fep->phydev, cmd);
int rc;
spin_lock_irqsave(&fep->lock, flags);
rc = mii_ethtool_gset(&fep->mii_if, cmd);
spin_unlock_irqrestore(&fep->lock, flags);
return rc;
} }
static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct fs_enet_private *fep = netdev_priv(dev); struct fs_enet_private *fep = netdev_priv(dev);
unsigned long flags; phy_ethtool_sset(fep->phydev, cmd);
int rc; return 0;
spin_lock_irqsave(&fep->lock, flags);
rc = mii_ethtool_sset(&fep->mii_if, cmd);
spin_unlock_irqrestore(&fep->lock, flags);
return rc;
} }
static int fs_nway_reset(struct net_device *dev) static int fs_nway_reset(struct net_device *dev)
{ {
struct fs_enet_private *fep = netdev_priv(dev); return 0;
return mii_nway_restart(&fep->mii_if);
} }
static u32 fs_get_msglevel(struct net_device *dev) static u32 fs_get_msglevel(struct net_device *dev)
...@@ -898,7 +935,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -898,7 +935,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&fep->lock, flags); spin_lock_irqsave(&fep->lock, flags);
rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); rc = phy_mii_ioctl(fep->phydev, mii, cmd);
spin_unlock_irqrestore(&fep->lock, flags); spin_unlock_irqrestore(&fep->lock, flags);
return rc; return rc;
} }
...@@ -1030,12 +1067,6 @@ static struct net_device *fs_init_instance(struct device *dev, ...@@ -1030,12 +1067,6 @@ static struct net_device *fs_init_instance(struct device *dev,
} }
registered = 1; registered = 1;
err = fs_mii_connect(ndev);
if (err != 0) {
printk(KERN_ERR DRV_MODULE_NAME
": %s fs_mii_connect failed.\n", ndev->name);
goto err;
}
return ndev; return ndev;
...@@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct net_device *ndev) ...@@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct net_device *ndev)
fpi = fep->fpi; fpi = fep->fpi;
fs_mii_disconnect(ndev);
unregister_netdev(ndev); unregister_netdev(ndev);
dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
...@@ -1196,17 +1225,39 @@ static int __init fs_init(void) ...@@ -1196,17 +1225,39 @@ static int __init fs_init(void)
r = setup_immap(); r = setup_immap();
if (r != 0) if (r != 0)
return r; return r;
r = driver_register(&fs_enet_fec_driver);
#ifdef CONFIG_FS_ENET_HAS_FCC
/* let's insert mii stuff */
r = fs_enet_mdio_bb_init();
if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME
"BB PHY init failed.\n");
return r;
}
r = driver_register(&fs_enet_fcc_driver);
if (r != 0) if (r != 0)
goto err; goto err;
#endif
r = driver_register(&fs_enet_fcc_driver); #ifdef CONFIG_FS_ENET_HAS_FEC
r = fs_enet_mdio_fec_init();
if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME
"FEC PHY init failed.\n");
return r;
}
r = driver_register(&fs_enet_fec_driver);
if (r != 0) if (r != 0)
goto err; goto err;
#endif
#ifdef CONFIG_FS_ENET_HAS_SCC
r = driver_register(&fs_enet_scc_driver); r = driver_register(&fs_enet_scc_driver);
if (r != 0) if (r != 0)
goto err; goto err;
#endif
return 0; return 0;
err: err:
......
This diff is collapsed.
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/phy.h>
#include <linux/fs_enet_pd.h> #include <linux/fs_enet_pd.h>
...@@ -12,12 +13,30 @@ ...@@ -12,12 +13,30 @@
#ifdef CONFIG_CPM1 #ifdef CONFIG_CPM1
#include <asm/commproc.h> #include <asm/commproc.h>
struct fec_info {
fec_t* fecp;
u32 mii_speed;
};
#endif #endif
#ifdef CONFIG_CPM2 #ifdef CONFIG_CPM2
#include <asm/cpm2.h> #include <asm/cpm2.h>
#endif #endif
/* This is used to operate with pins.
Note that the actual port size may
be different; cpm(s) handle it OK */
struct bb_info {
u8 mdio_dat_msk;
u8 mdio_dir_msk;
u8 *mdio_dir;
u8 *mdio_dat;
u8 mdc_msk;
u8 *mdc_dat;
int delay;
};
/* hw driver ops */ /* hw driver ops */
struct fs_ops { struct fs_ops {
int (*setup_data)(struct net_device *dev); int (*setup_data)(struct net_device *dev);
...@@ -25,6 +44,7 @@ struct fs_ops { ...@@ -25,6 +44,7 @@ struct fs_ops {
void (*free_bd)(struct net_device *dev); void (*free_bd)(struct net_device *dev);
void (*cleanup_data)(struct net_device *dev); void (*cleanup_data)(struct net_device *dev);
void (*set_multicast_list)(struct net_device *dev); void (*set_multicast_list)(struct net_device *dev);
void (*adjust_link)(struct net_device *dev);
void (*restart)(struct net_device *dev); void (*restart)(struct net_device *dev);
void (*stop)(struct net_device *dev); void (*stop)(struct net_device *dev);
void (*pre_request_irq)(struct net_device *dev, int irq); void (*pre_request_irq)(struct net_device *dev, int irq);
...@@ -100,10 +120,6 @@ struct fs_enet_mii_bus { ...@@ -100,10 +120,6 @@ struct fs_enet_mii_bus {
}; };
}; };
int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus);
int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
int fs_mii_fec_init(struct fs_enet_mii_bus *bus);
struct fs_enet_private { struct fs_enet_private {
struct device *dev; /* pointer back to the device (must be initialized first) */ struct device *dev; /* pointer back to the device (must be initialized first) */
spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t lock; /* during all ops except TX pckt processing */
...@@ -130,7 +146,8 @@ struct fs_enet_private { ...@@ -130,7 +146,8 @@ struct fs_enet_private {
struct fs_enet_mii_bus *mii_bus; struct fs_enet_mii_bus *mii_bus;
int interrupt; int interrupt;
int duplex, speed; /* current settings */ struct phy_device *phydev;
int oldduplex, oldspeed, oldlink; /* current settings */
/* event masks */ /* event masks */
u32 ev_napi_rx; /* mask of NAPI rx events */ u32 ev_napi_rx; /* mask of NAPI rx events */
...@@ -168,15 +185,9 @@ struct fs_enet_private { ...@@ -168,15 +185,9 @@ struct fs_enet_private {
}; };
/***************************************************************************/ /***************************************************************************/
int fs_enet_mdio_bb_init(void);
int fs_mii_read(struct net_device *dev, int phy_id, int location); int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); int fs_enet_mdio_fec_init(void);
void fs_mii_startup(struct net_device *dev);
void fs_mii_shutdown(struct net_device *dev);
void fs_mii_ack_int(struct net_device *dev);
void fs_mii_link_status_change_check(struct net_device *dev, int init_media);
void fs_init_bds(struct net_device *dev); void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev); void fs_cleanup_bds(struct net_device *dev);
...@@ -194,7 +205,6 @@ int fs_enet_platform_init(void); ...@@ -194,7 +205,6 @@ int fs_enet_platform_init(void);
void fs_enet_platform_cleanup(void); void fs_enet_platform_cleanup(void);
/***************************************************************************/ /***************************************************************************/
/* buffer descriptor access macros */ /* buffer descriptor access macros */
/* access macros */ /* access macros */
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/phy.h>
#include <asm/immap_cpm2.h> #include <asm/immap_cpm2.h>
#include <asm/mpc8260.h> #include <asm/mpc8260.h>
...@@ -122,22 +123,32 @@ static int do_pd_setup(struct fs_enet_private *fep) ...@@ -122,22 +123,32 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Attach the memory for the FCC Parameter RAM */ /* Attach the memory for the FCC Parameter RAM */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
fep->fcc.ep = (void *)r->start; fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.ep == NULL) if (fep->fcc.ep == NULL)
return -EINVAL; return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
fep->fcc.fccp = (void *)r->start; fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.fccp == NULL) if (fep->fcc.fccp == NULL)
return -EINVAL; return -EINVAL;
fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; if (fep->fpi->fcc_regs_c) {
fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
} else {
r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"fcc_regs_c");
fep->fcc.fcccp = (void *)ioremap(r->start,
r->end - r->start + 1);
}
if (fep->fcc.fcccp == NULL) if (fep->fcc.fcccp == NULL)
return -EINVAL; return -EINVAL;
fep->fcc.mem = (void *)fep->fpi->mem_offset;
if (fep->fcc.mem == NULL)
return -EINVAL;
return 0; return 0;
} }
...@@ -155,8 +166,6 @@ static int setup_data(struct net_device *dev) ...@@ -155,8 +166,6 @@ static int setup_data(struct net_device *dev)
if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
return -EINVAL; return -EINVAL;
fep->fcc.mem = (void *)fpi->mem_offset;
if (do_pd_setup(fep) != 0) if (do_pd_setup(fep) != 0)
return -EINVAL; return -EINVAL;
...@@ -394,7 +403,7 @@ static void restart(struct net_device *dev) ...@@ -394,7 +403,7 @@ static void restart(struct net_device *dev)
/* adjust to speed (for RMII mode) */ /* adjust to speed (for RMII mode) */
if (fpi->use_rmii) { if (fpi->use_rmii) {
if (fep->speed == 100) if (fep->phydev->speed == 100)
C8(fcccp, fcc_gfemr, 0x20); C8(fcccp, fcc_gfemr, 0x20);
else else
S8(fcccp, fcc_gfemr, 0x20); S8(fcccp, fcc_gfemr, 0x20);
...@@ -420,7 +429,7 @@ static void restart(struct net_device *dev) ...@@ -420,7 +429,7 @@ static void restart(struct net_device *dev)
S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); S32(fccp, fcc_fpsmr, FCC_PSMR_RMII);
/* adjust to duplex mode */ /* adjust to duplex mode */
if (fep->duplex) if (fep->phydev->duplex)
S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
else else
C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
...@@ -486,7 +495,10 @@ static void rx_bd_done(struct net_device *dev) ...@@ -486,7 +495,10 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev) static void tx_kickstart(struct net_device *dev)
{ {
/* nothing */ struct fs_enet_private *fep = netdev_priv(dev);
fcc_t *fccp = fep->fcc.fccp;
S32(fccp, fcc_ftodr, 0x80);
} }
static u32 get_int_events(struct net_device *dev) static u32 get_int_events(struct net_device *dev)
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#endif #endif
#include "fs_enet.h" #include "fs_enet.h"
#include "fec.h"
/*************************************************/ /*************************************************/
...@@ -75,50 +76,8 @@ ...@@ -75,50 +76,8 @@
/* clear bits */ /* clear bits */
#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v))
/* CRC polynomium used by the FEC for the multicast group filtering */
#define FEC_CRC_POLY 0x04C11DB7
#define FEC_MAX_MULTICAST_ADDRS 64
/* Interrupt events/masks.
*/
#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */
#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */
#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */
#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */
#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */
#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */
#define FEC_ENET_RXF 0x02000000U /* Full frame received */
#define FEC_ENET_RXB 0x01000000U /* A buffer was received */
#define FEC_ENET_MII 0x00800000U /* MII interrupt */
#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */
#define FEC_ECNTRL_PINMUX 0x00000004
#define FEC_ECNTRL_ETHER_EN 0x00000002
#define FEC_ECNTRL_RESET 0x00000001
#define FEC_RCNTRL_BC_REJ 0x00000010
#define FEC_RCNTRL_PROM 0x00000008
#define FEC_RCNTRL_MII_MODE 0x00000004
#define FEC_RCNTRL_DRT 0x00000002
#define FEC_RCNTRL_LOOP 0x00000001
#define FEC_TCNTRL_FDEN 0x00000004
#define FEC_TCNTRL_HBC 0x00000002
#define FEC_TCNTRL_GTS 0x00000001
/* Make MII read/write commands for the FEC.
*/
#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
#define mk_mii_end 0
#define FEC_MII_LOOPS 10000
/* /*
* Delay to wait for FEC reset command to complete (in us) * Delay to wait for FEC reset command to complete (in us)
*/ */
#define FEC_RESET_DELAY 50 #define FEC_RESET_DELAY 50
...@@ -303,13 +262,15 @@ static void restart(struct net_device *dev) ...@@ -303,13 +262,15 @@ static void restart(struct net_device *dev)
int r; int r;
u32 addrhi, addrlo; u32 addrhi, addrlo;
struct mii_bus* mii = fep->phydev->bus;
struct fec_info* fec_inf = mii->priv;
r = whack_reset(fep->fec.fecp); r = whack_reset(fep->fec.fecp);
if (r != 0) if (r != 0)
printk(KERN_ERR DRV_MODULE_NAME printk(KERN_ERR DRV_MODULE_NAME
": %s FEC Reset FAILED!\n", dev->name); ": %s FEC Reset FAILED!\n", dev->name);
/* /*
* Set station address. * Set station address.
*/ */
addrhi = ((u32) dev->dev_addr[0] << 24) | addrhi = ((u32) dev->dev_addr[0] << 24) |
((u32) dev->dev_addr[1] << 16) | ((u32) dev->dev_addr[1] << 16) |
...@@ -350,12 +311,12 @@ static void restart(struct net_device *dev) ...@@ -350,12 +311,12 @@ static void restart(struct net_device *dev)
FW(fecp, fun_code, 0x78000000); FW(fecp, fun_code, 0x78000000);
/* /*
* Set MII speed. * Set MII speed.
*/ */
FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); FW(fecp, mii_speed, fec_inf->mii_speed);
/* /*
* Clear any outstanding interrupt. * Clear any outstanding interrupt.
*/ */
FW(fecp, ievent, 0xffc0); FW(fecp, ievent, 0xffc0);
FW(fecp, ivec, (fep->interrupt / 2) << 29); FW(fecp, ivec, (fep->interrupt / 2) << 29);
...@@ -390,11 +351,12 @@ static void restart(struct net_device *dev) ...@@ -390,11 +351,12 @@ static void restart(struct net_device *dev)
} }
#endif #endif
FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
/* /*
* adjust to duplex mode * adjust to duplex mode
*/ */
if (fep->duplex) { if (fep->phydev->duplex) {
FC(fecp, r_cntrl, FEC_RCNTRL_DRT); FC(fecp, r_cntrl, FEC_RCNTRL_DRT);
FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */
} else { } else {
...@@ -418,9 +380,11 @@ static void restart(struct net_device *dev) ...@@ -418,9 +380,11 @@ static void restart(struct net_device *dev)
static void stop(struct net_device *dev) static void stop(struct net_device *dev)
{ {
struct fs_enet_private *fep = netdev_priv(dev); struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
fec_t *fecp = fep->fec.fecp; fec_t *fecp = fep->fec.fecp;
struct fs_enet_mii_bus *bus = fep->mii_bus;
const struct fs_mii_bus_info *bi = bus->bus_info; struct fec_info* feci= fep->phydev->bus->priv;
int i; int i;
if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0)
...@@ -444,11 +408,11 @@ static void stop(struct net_device *dev) ...@@ -444,11 +408,11 @@ static void stop(struct net_device *dev)
fs_cleanup_bds(dev); fs_cleanup_bds(dev);
/* shut down FEC1? that's where the mii bus is */ /* shut down FEC1? that's where the mii bus is */
if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { if (fpi->has_phy) {
FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
FW(fecp, ievent, FEC_ENET_MII); FW(fecp, ievent, FEC_ENET_MII);
FW(fecp, mii_speed, bus->fec.mii_speed); FW(fecp, mii_speed, feci->mii_speed);
} }
} }
...@@ -583,73 +547,3 @@ const struct fs_ops fs_fec_ops = { ...@@ -583,73 +547,3 @@ const struct fs_ops fs_fec_ops = {
.free_bd = free_bd, .free_bd = free_bd,
}; };
/***********************************************************************/
static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
{
fec_t *fecp = bus->fec.fecp;
int i, ret = -1;
if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
BUG();
/* Add PHY address to register command. */
FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
for (i = 0; i < FEC_MII_LOOPS; i++)
if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
break;
if (i < FEC_MII_LOOPS) {
FW(fecp, ievent, FEC_ENET_MII);
ret = FR(fecp, mii_data) & 0xffff;
}
return ret;
}
static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value)
{
fec_t *fecp = bus->fec.fecp;
int i;
/* this must never happen */
if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
BUG();
/* Add PHY address to register command. */
FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
for (i = 0; i < FEC_MII_LOOPS; i++)
if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
break;
if (i < FEC_MII_LOOPS)
FW(fecp, ievent, FEC_ENET_MII);
}
int fs_mii_fec_init(struct fs_enet_mii_bus *bus)
{
bd_t *bd = (bd_t *)__res;
const struct fs_mii_bus_info *bi = bus->bus_info;
fec_t *fecp;
if (bi->id != 0)
return -1;
bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec;
bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2)
& 0x3F) << 1;
fecp = bus->fec.fecp;
FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
FW(fecp, ievent, FEC_ENET_MII);
FW(fecp, mii_speed, bus->fec.mii_speed);
bus->mii_read = mii_read;
bus->mii_write = mii_write;
return 0;
}
...@@ -369,7 +369,7 @@ static void restart(struct net_device *dev) ...@@ -369,7 +369,7 @@ static void restart(struct net_device *dev)
W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22);
/* Set full duplex mode if needed */ /* Set full duplex mode if needed */
if (fep->duplex) if (fep->phydev->duplex)
S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE);
S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
...@@ -500,6 +500,8 @@ static void tx_restart(struct net_device *dev) ...@@ -500,6 +500,8 @@ static void tx_restart(struct net_device *dev)
scc_cr_cmd(fep, CPM_CR_RESTART_TX); scc_cr_cmd(fep, CPM_CR_RESTART_TX);
} }
/*************************************************************************/ /*************************************************************************/
const struct fs_ops fs_scc_ops = { const struct fs_ops fs_scc_ops = {
......
This diff is collapsed.
/*
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
*
* Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
* 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.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/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include "fs_enet.h"
#include "fec.h"
/* Make MII read/write commands for the FEC.
*/
#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
#define mk_mii_end 0
#define FEC_MII_LOOPS 10000
static int match_has_phy (struct device *dev, void* data)
{
struct platform_device* pdev = container_of(dev, struct platform_device, dev);
struct fs_platform_info* fpi;
if(strcmp(pdev->name, (char*)data))
{
return 0;
}
fpi = pdev->dev.platform_data;
if((fpi)&&(fpi->has_phy))
return 1;
return 0;
}
static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi)
{
struct resource *r;
fec_t *fecp;
char* name = "fsl-cpm-fec";
/* we need fec in order to be useful */
struct platform_device *fec_pdev =
container_of(bus_find_device(&platform_bus_type, NULL, name, match_has_phy),
struct platform_device, dev);
if(fec_pdev == NULL) {
printk(KERN_ERR"Unable to find PHY for %s", name);
return -ENODEV;
}
r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs");
fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t));
fec->mii_speed = fmpi->mii_speed;
setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
setbits32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
out_be32(&fecp->fec_ievent, FEC_ENET_MII);
out_be32(&fecp->fec_mii_speed, fec->mii_speed);
return 0;
}
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
struct fec_info* fec = bus->priv;
fec_t *fecp = fec->fecp;
int i, ret = -1;
if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
BUG();
/* Add PHY address to register command. */
out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location));
for (i = 0; i < FEC_MII_LOOPS; i++)
if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0)
break;
if (i < FEC_MII_LOOPS) {
out_be32(&fecp->fec_ievent, FEC_ENET_MII);
ret = in_be32(&fecp->fec_mii_data) & 0xffff;
}
return ret;
}
static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
struct fec_info* fec = bus->priv;
fec_t *fecp = fec->fecp;
int i;
/* this must never happen */
if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
BUG();
/* Add PHY address to register command. */
out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val));
for (i = 0; i < FEC_MII_LOOPS; i++)
if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0)
break;
if (i < FEC_MII_LOOPS)
out_be32(&fecp->fec_ievent, FEC_ENET_MII);
return 0;
}
static int fs_enet_fec_mii_reset(struct mii_bus *bus)
{
/* nothing here - for now */
return 0;
}
static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct fs_mii_fec_platform_info *pdata;
struct mii_bus *new_bus;
struct fec_info *fec;
int err = 0;
if (NULL == dev)
return -EINVAL;
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
if (NULL == new_bus)
return -ENOMEM;
fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
if (NULL == fec)
return -ENOMEM;
new_bus->name = "FEC MII Bus",
new_bus->read = &fs_enet_fec_mii_read,
new_bus->write = &fs_enet_fec_mii_write,
new_bus->reset = &fs_enet_fec_mii_reset,
new_bus->id = pdev->id;
pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data;
if (NULL == pdata) {
printk(KERN_ERR "fs_enet FEC mdio %d: Missing platform data!\n", pdev->id);
return -ENODEV;
}
/*set up workspace*/
fs_mii_fec_init(fec, pdata);
new_bus->priv = fec;
new_bus->irq = pdata->irq;
new_bus->dev = dev;
dev_set_drvdata(dev, new_bus);
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:
kfree(new_bus);
return err;
}
static int fs_enet_fec_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
mdiobus_unregister(bus);
dev_set_drvdata(dev, NULL);
kfree(bus->priv);
bus->priv = NULL;
kfree(bus);
return 0;
}
static struct device_driver fs_enet_fec_mdio_driver = {
.name = "fsl-cpm-fec-mdio",
.bus = &platform_bus_type,
.probe = fs_enet_fec_mdio_probe,
.remove = fs_enet_fec_mdio_remove,
};
int fs_enet_mdio_fec_init(void)
{
return driver_register(&fs_enet_fec_mdio_driver);
}
void fs_enet_mdio_fec_exit(void)
{
driver_unregister(&fs_enet_fec_mdio_driver);
}
/*
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
*
* Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
* 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.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/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include "fs_enet.h"
static const u16 mii_regs[7] = {
0x3100,
0x786d,
0x0fff,
0x0fff,
0x01e1,
0x45e1,
0x0003,
};
static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
{
int ret = 0;
if ((unsigned int)location >= ARRAY_SIZE(mii_regs))
return -1;
if (location != 5)
ret = mii_regs[location];
else
ret = bus->fixed.lpa;
return ret;
}
static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
{
/* do nothing */
}
int fs_mii_fixed_init(struct fs_enet_mii_bus *bus)
{
const struct fs_mii_bus_info *bi = bus->bus_info;
bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */
/* if speed is fixed at 10Mb, remove 100Mb modes */
if (bi->i.fixed.speed == 10)
bus->fixed.lpa &= ~LPA_100;
/* if duplex is half, remove full duplex modes */
if (bi->i.fixed.duplex == 0)
bus->fixed.lpa &= ~LPA_DUPLEX;
bus->mii_read = mii_read;
bus->mii_write = mii_write;
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment