Skip to content

Commit

Permalink
macb: initial support for Cadence GEM
Browse files Browse the repository at this point in the history
The Cadence GEM is based on the MACB Ethernet controller but has a few
small changes with regards to register and bitfield placement.  This
patch detects the presence of a GEM by reading the module ID register
and setting a flag appropriately.

This handles the new HW address, USRIO and hash register base register
locations in GEM.

v3: - convert to macb_is_gem() inline rather than storing a boolean
      flag
    - handle rx_overrun stats for gem

Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Tested-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
  • Loading branch information
Jamie Iles authored and Jamie Iles committed Nov 22, 2011
1 parent c220f8c commit f75ba50
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 27 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
obj-$(CONFIG_NET_VENDOR_AMD) += amd/
obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
obj-$(CONFIG_NET_ATMEL) += cadence/
obj-$(CONFIG_NET_CADENCE) += cadence/
obj-$(CONFIG_NET_BFIN) += adi/
obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/
Expand Down
16 changes: 9 additions & 7 deletions drivers/net/ethernet/cadence/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
config HAVE_NET_MACB
bool

config NET_ATMEL
bool "Atmel devices"
config NET_CADENCE
bool "Cadence devices"
depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200)
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
Expand All @@ -20,7 +20,7 @@ config NET_ATMEL
the remaining Atmel network card questions. If you say Y, you will be
asked for your specific card in the following questions.

if NET_ATMEL
if NET_CADENCE

config ARM_AT91_ETHER
tristate "AT91RM9200 Ethernet support"
Expand All @@ -32,14 +32,16 @@ config ARM_AT91_ETHER
ethernet support, then you should always answer Y to this.

config MACB
tristate "Atmel MACB support"
tristate "Cadence MACB/GEM support"
depends on HAVE_NET_MACB
select PHYLIB
---help---
The Atmel MACB ethernet interface is found on many AT32 and AT91
parts. Say Y to include support for the MACB chip.
The Cadence MACB ethernet interface is found on many Atmel AT32 and
AT91 parts. This driver also supports the Cadence GEM (Gigabit
Ethernet MAC found in some ARM SoC devices). Note: the Gigabit mode
is not yet supported. Say Y to include support for the MACB/GEM chip.

To compile this driver as a module, choose M here: the module
will be called macb.

endif # NET_ATMEL
endif # NET_CADENCE
43 changes: 24 additions & 19 deletions drivers/net/ethernet/cadence/macb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Atmel MACB Ethernet Controller driver
* Cadence MACB/GEM Ethernet Controller driver
*
* Copyright (C) 2004-2006 Atmel Corporation
*
Expand Down Expand Up @@ -59,9 +59,9 @@ static void __macb_set_hwaddr(struct macb *bp)
u16 top;

bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr));
macb_writel(bp, SA1B, bottom);
macb_or_gem_writel(bp, SA1B, bottom);
top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4)));
macb_writel(bp, SA1T, top);
macb_or_gem_writel(bp, SA1T, top);
}

static void __init macb_get_hwaddr(struct macb *bp)
Expand All @@ -70,8 +70,8 @@ static void __init macb_get_hwaddr(struct macb *bp)
u16 top;
u8 addr[6];

bottom = macb_readl(bp, SA1B);
top = macb_readl(bp, SA1T);
bottom = macb_or_gem_readl(bp, SA1B);
top = macb_or_gem_readl(bp, SA1T);

addr[0] = bottom & 0xff;
addr[1] = (bottom >> 8) & 0xff;
Expand Down Expand Up @@ -580,7 +580,10 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)

if (status & MACB_BIT(ISR_ROVR)) {
/* We missed at least one packet */
bp->hw_stats.rx_overruns++;
if (macb_is_gem(bp))
bp->hw_stats.gem.rx_overruns++;
else
bp->hw_stats.macb.rx_overruns++;
}

if (status & MACB_BIT(HRESP)) {
Expand Down Expand Up @@ -902,8 +905,8 @@ static void macb_sethashtable(struct net_device *dev)
mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
}

macb_writel(bp, HRB, mc_filter[0]);
macb_writel(bp, HRT, mc_filter[1]);
macb_or_gem_writel(bp, HRB, mc_filter[0]);
macb_or_gem_writel(bp, HRT, mc_filter[1]);
}

/*
Expand All @@ -925,17 +928,17 @@ static void macb_set_rx_mode(struct net_device *dev)

if (dev->flags & IFF_ALLMULTI) {
/* Enable all multicast mode */
macb_writel(bp, HRB, -1);
macb_writel(bp, HRT, -1);
macb_or_gem_writel(bp, HRB, -1);
macb_or_gem_writel(bp, HRT, -1);
cfg |= MACB_BIT(NCFGR_MTI);
} else if (!netdev_mc_empty(dev)) {
/* Enable specific multicasts */
macb_sethashtable(dev);
cfg |= MACB_BIT(NCFGR_MTI);
} else if (dev->flags & (~IFF_ALLMULTI)) {
/* Disable all multicast mode */
macb_writel(bp, HRB, 0);
macb_writel(bp, HRT, 0);
macb_or_gem_writel(bp, HRB, 0);
macb_or_gem_writel(bp, HRT, 0);
cfg &= ~MACB_BIT(NCFGR_MTI);
}

Expand Down Expand Up @@ -1196,15 +1199,16 @@ static int __init macb_probe(struct platform_device *pdev)

if (pdata && pdata->is_rmii)
#if defined(CONFIG_ARCH_AT91)
macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) |
MACB_BIT(CLKEN)));
#else
macb_writel(bp, USRIO, 0);
macb_or_gem_writel(bp, USRIO, 0);
#endif
else
#if defined(CONFIG_ARCH_AT91)
macb_writel(bp, USRIO, MACB_BIT(CLKEN));
macb_or_gem_writel(bp, USRIO, MACB_BIT(CLKEN));
#else
macb_writel(bp, USRIO, MACB_BIT(MII));
macb_or_gem_writel(bp, USRIO, MACB_BIT(MII));
#endif

bp->tx_pending = DEF_TX_RING_PENDING;
Expand All @@ -1221,8 +1225,9 @@ static int __init macb_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, dev);

netdev_info(dev, "Atmel MACB at 0x%08lx irq %d (%pM)\n",
dev->base_addr, dev->irq, dev->dev_addr);
netdev_info(dev, "Cadence %s at 0x%08lx irq %d (%pM)\n",
macb_is_gem(bp) ? "GEM" : "MACB", dev->base_addr,
dev->irq, dev->dev_addr);

phydev = bp->phy_dev;
netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
Expand Down Expand Up @@ -1332,6 +1337,6 @@ module_init(macb_init);
module_exit(macb_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel MACB Ethernet driver");
MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_ALIAS("platform:macb");
61 changes: 61 additions & 0 deletions drivers/net/ethernet/cadence/macb.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@
#define MACB_TPQ 0x00bc
#define MACB_USRIO 0x00c0
#define MACB_WOL 0x00c4
#define MACB_MID 0x00fc

/* GEM register offsets. */
#define GEM_NCFGR 0x0004
#define GEM_USRIO 0x000c
#define GEM_HRB 0x0080
#define GEM_HRT 0x0084
#define GEM_SA1B 0x0088
#define GEM_SA1T 0x008C

/* Bitfields in NCR */
#define MACB_LB_OFFSET 0
Expand Down Expand Up @@ -228,6 +237,12 @@
#define MACB_WOL_MTI_OFFSET 19
#define MACB_WOL_MTI_SIZE 1

/* Bitfields in MID */
#define MACB_IDNUM_OFFSET 16
#define MACB_IDNUM_SIZE 16
#define MACB_REV_OFFSET 0
#define MACB_REV_SIZE 16

/* Constants for CLK */
#define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1
Expand All @@ -254,11 +269,52 @@
<< MACB_##name##_OFFSET)) \
| MACB_BF(name,value))

#define GEM_BIT(name) \
(1 << GEM_##name##_OFFSET)
#define GEM_BF(name, value) \
(((value) & ((1 << GEM_##name##_SIZE) - 1)) \
<< GEM_##name##_OFFSET)
#define GEM_BFEXT(name, value)\
(((value) >> GEM_##name##_OFFSET) \
& ((1 << GEM_##name##_SIZE) - 1))
#define GEM_BFINS(name, value, old) \
(((old) & ~(((1 << GEM_##name##_SIZE) - 1) \
<< GEM_##name##_OFFSET)) \
| GEM_BF(name, value))

/* Register access macros */
#define macb_readl(port,reg) \
__raw_readl((port)->regs + MACB_##reg)
#define macb_writel(port,reg,value) \
__raw_writel((value), (port)->regs + MACB_##reg)
#define gem_readl(port, reg) \
__raw_readl((port)->regs + GEM_##reg)
#define gem_writel(port, reg, value) \
__raw_writel((value), (port)->regs + GEM_##reg)

/*
* Conditional GEM/MACB macros. These perform the operation to the correct
* register dependent on whether the device is a GEM or a MACB. For registers
* and bitfields that are common across both devices, use macb_{read,write}l
* to avoid the cost of the conditional.
*/
#define macb_or_gem_writel(__bp, __reg, __value) \
({ \
if (macb_is_gem((__bp))) \
gem_writel((__bp), __reg, __value); \
else \
macb_writel((__bp), __reg, __value); \
})

#define macb_or_gem_readl(__bp, __reg) \
({ \
u32 __v; \
if (macb_is_gem((__bp))) \
__v = gem_readl((__bp), __reg); \
else \
__v = macb_readl((__bp), __reg); \
__v; \
})

struct dma_desc {
u32 addr;
Expand Down Expand Up @@ -391,4 +447,9 @@ struct macb {
unsigned int duplex;
};

static inline bool macb_is_gem(struct macb *bp)
{
return MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2;
}

#endif /* _MACB_H */

0 comments on commit f75ba50

Please sign in to comment.