/*
* Driver for the MPC5200 Fast Ethernet Controller
*
* Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
* now maintained by Sylvain Munaut <tnt@246tNt.com>
*
* Copyright (C) 2007 Domen Puncer, Telargo, Inc.
* Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2003-2004 MontaVista, Software, Inc.
*
* 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/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/crc32.h>
#include <linux/hardirq.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/mpc52xx.h>
#include <sysdev/bestcomm/bestcomm.h>
#include <sysdev/bestcomm/fec.h>
#include "fec_mpc52xx.h"
#define DRIVER_NAME "mpc52xx-fec"
/* Private driver data structure */
struct mpc52xx_fec_priv {
struct net_device *ndev;
int duplex;
int speed;
int r_irq;
int t_irq;
struct mpc52xx_fec __iomem *fec;
struct bcom_task *rx_dmatsk;
struct bcom_task *tx_dmatsk;
spinlock_t lock;
int msg_enable;
/* MDIO link details */
unsigned int mdio_speed;
struct device_node *phy_node;
struct phy_device *phydev;
enum phy_state link;
int seven_wire_mode;
};
static irqreturn_t mpc52xx_fec_interrupt(int, void *);
static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
static void mpc52xx_fec_stop(struct net_device *dev);
static void mpc52xx_fec_start(struct net_device *dev);
static void mpc52xx_fec_reset(struct net_device *dev);
static u8 mpc52xx_fec_mac_addr[6];
module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0);
MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe");
#define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \
NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP)
static int debug = -1; /* the above default */
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debugging messages level");
static void mpc52xx_fec_tx_timeout(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
unsigned long flags;
dev_warn(&dev->dev, "transmit timed out\n");
spin_lock_irqsave(&priv->lock, flags);
mpc52xx_fec_reset(dev);
dev->stats.tx_errors++;
spin_unlock_irqrestore(&priv->lock, flags);
netif_wake_queue(dev);
}
static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct mpc52xx_fec __iomem *fec = priv->fec;
out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
}
static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct mpc52xx_fec __iomem *fec = priv->fec;
*(u32 *)(&mac[0]) = in_be32(&fec->paddr1);
*(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
}
static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sock = addr;
memcpy(