MIPS: BCM63xx: Add integrated ethernet mac support.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Maxime Bizon 2009-08-18 13:23:40 +01:00 committed by Ralf Baechle
parent e7300d04bd
commit 9b1fc55a05
6 changed files with 2444 additions and 1 deletions

View file

@ -1,5 +1,5 @@
obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
dev-dsp.o
dev-dsp.o dev-enet.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += boards/

View file

@ -0,0 +1,159 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <bcm63xx_dev_enet.h>
#include <bcm63xx_io.h>
#include <bcm63xx_regs.h>
static struct resource shared_res[] = {
{
.start = -1, /* filled at runtime */
.end = -1, /* filled at runtime */
.flags = IORESOURCE_MEM,
},
};
static struct platform_device bcm63xx_enet_shared_device = {
.name = "bcm63xx_enet_shared",
.id = 0,
.num_resources = ARRAY_SIZE(shared_res),
.resource = shared_res,
};
static int shared_device_registered;
static struct resource enet0_res[] = {
{
.start = -1, /* filled at runtime */
.end = -1, /* filled at runtime */
.flags = IORESOURCE_MEM,
},
{
.start = -1, /* filled at runtime */
.flags = IORESOURCE_IRQ,
},
{
.start = -1, /* filled at runtime */
.flags = IORESOURCE_IRQ,
},
{
.start = -1, /* filled at runtime */
.flags = IORESOURCE_IRQ,
},
};
static struct bcm63xx_enet_platform_data enet0_pd;
static struct platform_device bcm63xx_enet0_device = {
.name = "bcm63xx_enet",
.id = 0,
.num_resources = ARRAY_SIZE(enet0_res),
.resource = enet0_res,
.dev = {
.platform_data = &enet0_pd,
},
};
static struct resource enet1_res[] = {
{
.start = -1, /* filled at runtime */
.end = -1, /* filled at runtime */
.flags = IORESOURCE_MEM,
},
{
.start = -1, /* filled at runtime */
.flags = IORESOURCE_IRQ,
},
{
.start = -1, /* filled at runtime */
.flags = IORESOURCE_IRQ,
},
{
.start = -1, /* filled at runtime */
.flags = IORESOURCE_IRQ,
},
};
static struct bcm63xx_enet_platform_data enet1_pd;
static struct platform_device bcm63xx_enet1_device = {
.name = "bcm63xx_enet",
.id = 1,
.num_resources = ARRAY_SIZE(enet1_res),
.resource = enet1_res,
.dev = {
.platform_data = &enet1_pd,
},
};
int __init bcm63xx_enet_register(int unit,
const struct bcm63xx_enet_platform_data *pd)
{
struct platform_device *pdev;
struct bcm63xx_enet_platform_data *dpd;
int ret;
if (unit > 1)
return -ENODEV;
if (!shared_device_registered) {
shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
shared_res[0].end = shared_res[0].start;
if (BCMCPU_IS_6338())
shared_res[0].end += (RSET_ENETDMA_SIZE / 2) - 1;
else
shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
ret = platform_device_register(&bcm63xx_enet_shared_device);
if (ret)
return ret;
shared_device_registered = 1;
}
if (unit == 0) {
enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
enet0_res[0].end = enet0_res[0].start;
enet0_res[0].end += RSET_ENET_SIZE - 1;
enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0);
enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA);
enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA);
pdev = &bcm63xx_enet0_device;
} else {
enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1);
enet1_res[0].end = enet1_res[0].start;
enet1_res[0].end += RSET_ENET_SIZE - 1;
enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1);
enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA);
enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA);
pdev = &bcm63xx_enet1_device;
}
/* copy given platform data */
dpd = pdev->dev.platform_data;
memcpy(dpd, pd, sizeof(*pd));
/* adjust them in case internal phy is used */
if (dpd->use_internal_phy) {
/* internal phy only exists for enet0 */
if (unit == 1)
return -ENODEV;
dpd->phy_id = 1;
dpd->has_phy_interrupt = 1;
dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);
}
ret = platform_device_register(pdev);
if (ret)
return ret;
return 0;
}

View file

@ -1934,6 +1934,15 @@ config XILINX_EMACLITE
help
This driver supports the 10/100 Ethernet Lite from Xilinx.
config BCM63XX_ENET
tristate "Broadcom 63xx internal mac support"
depends on BCM63XX
select MII
select PHYLIB
help
This driver supports the ethernet MACs in the Broadcom 63xx
MIPS chipset family (BCM63XX).
source "drivers/net/fs_enet/Kconfig"
endif # NET_ETHERNET

View file

@ -137,6 +137,7 @@ obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_AX88796) += ax88796.o
obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o

1971
drivers/net/bcm63xx_enet.c Normal file

File diff suppressed because it is too large Load diff

303
drivers/net/bcm63xx_enet.h Normal file
View file

@ -0,0 +1,303 @@
#ifndef BCM63XX_ENET_H_
#define BCM63XX_ENET_H_
#include <linux/types.h>
#include <linux/mii.h>
#include <linux/mutex.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <bcm63xx_regs.h>
#include <bcm63xx_irq.h>
#include <bcm63xx_io.h>
/* default number of descriptor */
#define BCMENET_DEF_RX_DESC 64
#define BCMENET_DEF_TX_DESC 32
/* maximum burst len for dma (4 bytes unit) */
#define BCMENET_DMA_MAXBURST 16
/* tx transmit threshold (4 bytes unit), fifo is 256 bytes, the value
* must be low enough so that a DMA transfer of above burst length can
* not overflow the fifo */
#define BCMENET_TX_FIFO_TRESH 32
/*
* hardware maximum rx/tx packet size including FCS, max mtu is
* actually 2047, but if we set max rx size register to 2047 we won't
* get overflow information if packet size is 2048 or above
*/
#define BCMENET_MAX_MTU 2046
/*
* rx/tx dma descriptor
*/
struct bcm_enet_desc {
u32 len_stat;
u32 address;
};
#define DMADESC_LENGTH_SHIFT 16
#define DMADESC_LENGTH_MASK (0xfff << DMADESC_LENGTH_SHIFT)
#define DMADESC_OWNER_MASK (1 << 15)
#define DMADESC_EOP_MASK (1 << 14)
#define DMADESC_SOP_MASK (1 << 13)
#define DMADESC_ESOP_MASK (DMADESC_EOP_MASK | DMADESC_SOP_MASK)
#define DMADESC_WRAP_MASK (1 << 12)
#define DMADESC_UNDER_MASK (1 << 9)
#define DMADESC_APPEND_CRC (1 << 8)
#define DMADESC_OVSIZE_MASK (1 << 4)
#define DMADESC_RXER_MASK (1 << 2)
#define DMADESC_CRC_MASK (1 << 1)
#define DMADESC_OV_MASK (1 << 0)
#define DMADESC_ERR_MASK (DMADESC_UNDER_MASK | \
DMADESC_OVSIZE_MASK | \
DMADESC_RXER_MASK | \
DMADESC_CRC_MASK | \
DMADESC_OV_MASK)
/*
* MIB Counters register definitions
*/
#define ETH_MIB_TX_GD_OCTETS 0
#define ETH_MIB_TX_GD_PKTS 1
#define ETH_MIB_TX_ALL_OCTETS 2
#define ETH_MIB_TX_ALL_PKTS 3
#define ETH_MIB_TX_BRDCAST 4
#define ETH_MIB_TX_MULT 5
#define ETH_MIB_TX_64 6
#define ETH_MIB_TX_65_127 7
#define ETH_MIB_TX_128_255 8
#define ETH_MIB_TX_256_511 9
#define ETH_MIB_TX_512_1023 10
#define ETH_MIB_TX_1024_MAX 11
#define ETH_MIB_TX_JAB 12
#define ETH_MIB_TX_OVR 13
#define ETH_MIB_TX_FRAG 14
#define ETH_MIB_TX_UNDERRUN 15
#define ETH_MIB_TX_COL 16
#define ETH_MIB_TX_1_COL 17
#define ETH_MIB_TX_M_COL 18
#define ETH_MIB_TX_EX_COL 19
#define ETH_MIB_TX_LATE 20
#define ETH_MIB_TX_DEF 21
#define ETH_MIB_TX_CRS 22
#define ETH_MIB_TX_PAUSE 23
#define ETH_MIB_RX_GD_OCTETS 32
#define ETH_MIB_RX_GD_PKTS 33
#define ETH_MIB_RX_ALL_OCTETS 34
#define ETH_MIB_RX_ALL_PKTS 35
#define ETH_MIB_RX_BRDCAST 36
#define ETH_MIB_RX_MULT 37
#define ETH_MIB_RX_64 38
#define ETH_MIB_RX_65_127 39
#define ETH_MIB_RX_128_255 40
#define ETH_MIB_RX_256_511 41
#define ETH_MIB_RX_512_1023 42
#define ETH_MIB_RX_1024_MAX 43
#define ETH_MIB_RX_JAB 44
#define ETH_MIB_RX_OVR 45
#define ETH_MIB_RX_FRAG 46
#define ETH_MIB_RX_DROP 47
#define ETH_MIB_RX_CRC_ALIGN 48
#define ETH_MIB_RX_UND 49
#define ETH_MIB_RX_CRC 50
#define ETH_MIB_RX_ALIGN 51
#define ETH_MIB_RX_SYM 52
#define ETH_MIB_RX_PAUSE 53
#define ETH_MIB_RX_CNTRL 54
struct bcm_enet_mib_counters {
u64 tx_gd_octets;
u32 tx_gd_pkts;
u32 tx_all_octets;
u32 tx_all_pkts;
u32 tx_brdcast;
u32 tx_mult;
u32 tx_64;
u32 tx_65_127;
u32 tx_128_255;
u32 tx_256_511;
u32 tx_512_1023;
u32 tx_1024_max;
u32 tx_jab;
u32 tx_ovr;
u32 tx_frag;
u32 tx_underrun;
u32 tx_col;
u32 tx_1_col;
u32 tx_m_col;
u32 tx_ex_col;
u32 tx_late;
u32 tx_def;
u32 tx_crs;
u32 tx_pause;
u64 rx_gd_octets;
u32 rx_gd_pkts;
u32 rx_all_octets;
u32 rx_all_pkts;
u32 rx_brdcast;
u32 rx_mult;
u32 rx_64;
u32 rx_65_127;
u32 rx_128_255;
u32 rx_256_511;
u32 rx_512_1023;
u32 rx_1024_max;
u32 rx_jab;
u32 rx_ovr;
u32 rx_frag;
u32 rx_drop;
u32 rx_crc_align;
u32 rx_und;
u32 rx_crc;
u32 rx_align;
u32 rx_sym;
u32 rx_pause;
u32 rx_cntrl;
};
struct bcm_enet_priv {
/* mac id (from platform device id) */
int mac_id;
/* base remapped address of device */
void __iomem *base;
/* mac irq, rx_dma irq, tx_dma irq */
int irq;
int irq_rx;
int irq_tx;
/* hw view of rx & tx dma ring */
dma_addr_t rx_desc_dma;
dma_addr_t tx_desc_dma;
/* allocated size (in bytes) for rx & tx dma ring */
unsigned int rx_desc_alloc_size;
unsigned int tx_desc_alloc_size;
struct napi_struct napi;
/* dma channel id for rx */
int rx_chan;
/* number of dma desc in rx ring */
int rx_ring_size;
/* cpu view of rx dma ring */
struct bcm_enet_desc *rx_desc_cpu;
/* current number of armed descriptor given to hardware for rx */
int rx_desc_count;
/* next rx descriptor to fetch from hardware */
int rx_curr_desc;
/* next dirty rx descriptor to refill */
int rx_dirty_desc;
/* size of allocated rx skbs */
unsigned int rx_skb_size;
/* list of skb given to hw for rx */
struct sk_buff **rx_skb;
/* used when rx skb allocation failed, so we defer rx queue
* refill */
struct timer_list rx_timeout;
/* lock rx_timeout against rx normal operation */
spinlock_t rx_lock;
/* dma channel id for tx */
int tx_chan;
/* number of dma desc in tx ring */
int tx_ring_size;
/* cpu view of rx dma ring */
struct bcm_enet_desc *tx_desc_cpu;
/* number of available descriptor for tx */
int tx_desc_count;
/* next tx descriptor avaiable */
int tx_curr_desc;
/* next dirty tx descriptor to reclaim */
int tx_dirty_desc;
/* list of skb given to hw for tx */
struct sk_buff **tx_skb;
/* lock used by tx reclaim and xmit */
spinlock_t tx_lock;
/* set if internal phy is ignored and external mii interface
* is selected */
int use_external_mii;
/* set if a phy is connected, phy address must be known,
* probing is not possible */
int has_phy;
int phy_id;
/* set if connected phy has an associated irq */
int has_phy_interrupt;
int phy_interrupt;
/* used when a phy is connected (phylib used) */
struct mii_bus *mii_bus;
struct phy_device *phydev;
int old_link;
int old_duplex;
int old_pause;
/* used when no phy is connected */
int force_speed_100;
int force_duplex_full;
/* pause parameters */
int pause_auto;
int pause_rx;
int pause_tx;
/* stats */
struct net_device_stats stats;
struct bcm_enet_mib_counters mib;
/* after mib interrupt, mib registers update is done in this
* work queue */
struct work_struct mib_update_task;
/* lock mib update between userspace request and workqueue */
struct mutex mib_update_lock;
/* mac clock */
struct clk *mac_clk;
/* phy clock if internal phy is used */
struct clk *phy_clk;
/* network device reference */
struct net_device *net_dev;
/* platform device reference */
struct platform_device *pdev;
/* maximum hardware transmit/receive size */
unsigned int hw_mtu;
};
#endif /* ! BCM63XX_ENET_H_ */