From f75ba50bdc2bcfab591bdf903312557033d0ac68 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 8 Nov 2011 10:12:32 +0000 Subject: macb: initial support for Cadence GEM 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 Acked-by: Nicolas Ferre Cc: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Jamie Iles Tested-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/net/ethernet/Makefile | 2 +- drivers/net/ethernet/cadence/Kconfig | 16 +++++----- drivers/net/ethernet/cadence/macb.c | 43 ++++++++++++++----------- drivers/net/ethernet/cadence/macb.h | 61 ++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index be5dde040261..94b7f287d6c5 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -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/ diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index 98849a1fc749..a2e150059bc7 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -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. @@ -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" @@ -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 diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index aa1d597091a8..4e61a8610d6a 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1,5 +1,5 @@ /* - * Atmel MACB Ethernet Controller driver + * Cadence MACB/GEM Ethernet Controller driver * * Copyright (C) 2004-2006 Atmel Corporation * @@ -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) @@ -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; @@ -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)) { @@ -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]); } /* @@ -925,8 +928,8 @@ 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 */ @@ -934,8 +937,8 @@ static void macb_set_rx_mode(struct net_device *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); } @@ -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; @@ -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", @@ -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"); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d3212f6db703..d50057c244b2 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -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 @@ -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 @@ -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; @@ -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 */ -- cgit v1.2.1 From 70c9f3d4372ffa90775603e9c4e055a26a9b83e1 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 9 Mar 2011 16:22:54 +0000 Subject: macb: support higher rate GEM MDIO clock divisors GEM devices support larger clock divisors and have a different range of divisors. Program the MDIO clock divisors based on the device type. Signed-off-by: Jamie Iles Acked-by: David S. Miller Acked-by: Nicolas Ferre Tested-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/net/ethernet/cadence/macb.c | 55 +++++++++++++++++++++++++++++-------- drivers/net/ethernet/cadence/macb.h | 11 ++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4e61a8610d6a..c5c3eb450c1b 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -793,6 +793,48 @@ static void macb_reset_hw(struct macb *bp) macb_readl(bp, ISR); } +static u32 gem_mdc_clk_div(struct macb *bp) +{ + u32 config; + unsigned long pclk_hz = clk_get_rate(bp->pclk); + + if (pclk_hz <= 20000000) + config = GEM_BF(CLK, GEM_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = GEM_BF(CLK, GEM_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = GEM_BF(CLK, GEM_CLK_DIV32); + else if (pclk_hz <= 120000000) + config = GEM_BF(CLK, GEM_CLK_DIV48); + else if (pclk_hz <= 160000000) + config = GEM_BF(CLK, GEM_CLK_DIV64); + else + config = GEM_BF(CLK, GEM_CLK_DIV96); + + return config; +} + +static u32 macb_mdc_clk_div(struct macb *bp) +{ + u32 config; + unsigned long pclk_hz; + + if (macb_is_gem(bp)) + return gem_mdc_clk_div(bp); + + pclk_hz = clk_get_rate(bp->pclk); + if (pclk_hz <= 20000000) + config = MACB_BF(CLK, MACB_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = MACB_BF(CLK, MACB_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = MACB_BF(CLK, MACB_CLK_DIV32); + else + config = MACB_BF(CLK, MACB_CLK_DIV64); + + return config; +} + static void macb_init_hw(struct macb *bp) { u32 config; @@ -800,7 +842,7 @@ static void macb_init_hw(struct macb *bp) macb_reset_hw(bp); __macb_set_hwaddr(bp); - config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L); + config = macb_mdc_clk_div(bp); config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ config |= MACB_BIT(BIG); /* Receive oversized frames */ @@ -1119,7 +1161,6 @@ static int __init macb_probe(struct platform_device *pdev) struct net_device *dev; struct macb *bp; struct phy_device *phydev; - unsigned long pclk_hz; u32 config; int err = -ENXIO; @@ -1183,15 +1224,7 @@ static int __init macb_probe(struct platform_device *pdev) dev->base_addr = regs->start; /* Set MII management clock divider */ - pclk_hz = clk_get_rate(bp->pclk); - if (pclk_hz <= 20000000) - config = MACB_BF(CLK, MACB_CLK_DIV8); - else if (pclk_hz <= 40000000) - config = MACB_BF(CLK, MACB_CLK_DIV16); - else if (pclk_hz <= 80000000) - config = MACB_BF(CLK, MACB_CLK_DIV32); - else - config = MACB_BF(CLK, MACB_CLK_DIV64); + config = macb_mdc_clk_div(bp); macb_writel(bp, NCFGR, config); macb_get_hwaddr(bp); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d50057c244b2..354ed8f77884 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -135,6 +135,9 @@ #define MACB_IRXFCS_OFFSET 19 #define MACB_IRXFCS_SIZE 1 +/* GEM specific NCFGR bitfields. */ +#define GEM_CLK_OFFSET 18 +#define GEM_CLK_SIZE 3 /* Bitfields in NSR */ #define MACB_NSR_LINK_OFFSET 0 #define MACB_NSR_LINK_SIZE 1 @@ -249,6 +252,14 @@ #define MACB_CLK_DIV32 2 #define MACB_CLK_DIV64 3 +/* GEM specific constants for CLK. */ +#define GEM_CLK_DIV8 0 +#define GEM_CLK_DIV16 1 +#define GEM_CLK_DIV32 2 +#define GEM_CLK_DIV48 3 +#define GEM_CLK_DIV64 4 +#define GEM_CLK_DIV96 5 + /* Constants for MAN register */ #define MACB_MAN_SOF 1 #define MACB_MAN_WRITE 1 -- cgit v1.2.1 From a494ed8e25759f05f5a419d675f198e4359ef6fc Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 9 Mar 2011 16:26:35 +0000 Subject: macb: support statistics for GEM devices GEM devices have a different number of statistics registers and they are at a different offset to MACB devices. Make the statistics collection method dependent on device type. Signed-off-by: Jamie Iles Acked-by: David S. Miller Acked-by: Nicolas Ferre Tested-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/net/ethernet/cadence/macb.c | 57 +++++++++++++++++++++++++++++++++++-- drivers/net/ethernet/cadence/macb.h | 54 ++++++++++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index c5c3eb450c1b..6a7d3eae8cc7 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -285,8 +285,8 @@ err_out: static void macb_update_stats(struct macb *bp) { u32 __iomem *reg = bp->regs + MACB_PFR; - u32 *p = &bp->hw_stats.rx_pause_frames; - u32 *end = &bp->hw_stats.tx_pause_frames + 1; + u32 *p = &bp->hw_stats.macb.rx_pause_frames; + u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1; WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); @@ -1042,11 +1042,62 @@ static int macb_close(struct net_device *dev) return 0; } +static void gem_update_stats(struct macb *bp) +{ + u32 __iomem *reg = bp->regs + GEM_OTX; + u32 *p = &bp->hw_stats.gem.tx_octets_31_0; + u32 *end = &bp->hw_stats.gem.rx_udp_checksum_errors + 1; + + for (; p < end; p++, reg++) + *p += __raw_readl(reg); +} + +static struct net_device_stats *gem_get_stats(struct macb *bp) +{ + struct gem_stats *hwstat = &bp->hw_stats.gem; + struct net_device_stats *nstat = &bp->stats; + + gem_update_stats(bp); + + nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors + + hwstat->rx_alignment_errors + + hwstat->rx_resource_errors + + hwstat->rx_overruns + + hwstat->rx_oversize_frames + + hwstat->rx_jabbers + + hwstat->rx_undersized_frames + + hwstat->rx_length_field_frame_errors); + nstat->tx_errors = (hwstat->tx_late_collisions + + hwstat->tx_excessive_collisions + + hwstat->tx_underrun + + hwstat->tx_carrier_sense_errors); + nstat->multicast = hwstat->rx_multicast_frames; + nstat->collisions = (hwstat->tx_single_collision_frames + + hwstat->tx_multiple_collision_frames + + hwstat->tx_excessive_collisions); + nstat->rx_length_errors = (hwstat->rx_oversize_frames + + hwstat->rx_jabbers + + hwstat->rx_undersized_frames + + hwstat->rx_length_field_frame_errors); + nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors; + nstat->rx_frame_errors = hwstat->rx_alignment_errors; + nstat->rx_fifo_errors = hwstat->rx_overruns; + nstat->tx_aborted_errors = hwstat->tx_excessive_collisions; + nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors; + nstat->tx_fifo_errors = hwstat->tx_underrun; + + return nstat; +} + static struct net_device_stats *macb_get_stats(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct net_device_stats *nstat = &bp->stats; - struct macb_stats *hwstat = &bp->hw_stats; + struct macb_stats *hwstat = &bp->hw_stats.macb; + + if (macb_is_gem(bp)) + return gem_get_stats(bp); /* read stats from hardware */ macb_update_stats(bp); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 354ed8f77884..1367b92edb3d 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -68,6 +68,7 @@ #define GEM_HRT 0x0084 #define GEM_SA1B 0x0088 #define GEM_SA1T 0x008C +#define GEM_OTX 0x0100 /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 @@ -425,6 +426,54 @@ struct macb_stats { u32 tx_pause_frames; }; +struct gem_stats { + u32 tx_octets_31_0; + u32 tx_octets_47_32; + u32 tx_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_64_byte_frames; + u32 tx_65_127_byte_frames; + u32 tx_128_255_byte_frames; + u32 tx_256_511_byte_frames; + u32 tx_512_1023_byte_frames; + u32 tx_1024_1518_byte_frames; + u32 tx_greater_than_1518_byte_frames; + u32 tx_underrun; + u32 tx_single_collision_frames; + u32 tx_multiple_collision_frames; + u32 tx_excessive_collisions; + u32 tx_late_collisions; + u32 tx_deferred_frames; + u32 tx_carrier_sense_errors; + u32 rx_octets_31_0; + u32 rx_octets_47_32; + u32 rx_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_64_byte_frames; + u32 rx_65_127_byte_frames; + u32 rx_128_255_byte_frames; + u32 rx_256_511_byte_frames; + u32 rx_512_1023_byte_frames; + u32 rx_1024_1518_byte_frames; + u32 rx_greater_than_1518_byte_frames; + u32 rx_undersized_frames; + u32 rx_oversize_frames; + u32 rx_jabbers; + u32 rx_frame_check_sequence_errors; + u32 rx_length_field_frame_errors; + u32 rx_symbol_errors; + u32 rx_alignment_errors; + u32 rx_resource_errors; + u32 rx_overruns; + u32 rx_ip_header_checksum_errors; + u32 rx_tcp_checksum_errors; + u32 rx_udp_checksum_errors; +}; + struct macb { void __iomem *regs; @@ -443,7 +492,10 @@ struct macb { struct net_device *dev; struct napi_struct napi; struct net_device_stats stats; - struct macb_stats hw_stats; + union { + struct macb_stats macb; + struct gem_stats gem; + } hw_stats; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; -- cgit v1.2.1 From 757a03c6e004fbbdef872cb7ecdc940a891b8e6e Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 9 Mar 2011 16:29:59 +0000 Subject: macb: support DMA bus widths > 32 bits Some GEM implementations may support DMA bus widths up to 128 bits. We can get the maximum supported DMA bus width from the design configuration register so use that to program the device up. Signed-off-by: Jamie Iles Acked-by: David S. Miller Acked-by: Nicolas Ferre Tested-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/net/ethernet/cadence/macb.c | 23 +++++++++++++++++++++++ drivers/net/ethernet/cadence/macb.h | 19 +++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 6a7d3eae8cc7..38f1932013d1 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -835,6 +835,27 @@ static u32 macb_mdc_clk_div(struct macb *bp) return config; } +/* + * Get the DMA bus width field of the network configuration register that we + * should program. We find the width from decoding the design configuration + * register to find the maximum supported data bus width. + */ +static u32 macb_dbw(struct macb *bp) +{ + if (!macb_is_gem(bp)) + return 0; + + switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) { + case 4: + return GEM_BF(DBW, GEM_DBW128); + case 2: + return GEM_BF(DBW, GEM_DBW64); + case 1: + default: + return GEM_BF(DBW, GEM_DBW32); + } +} + static void macb_init_hw(struct macb *bp) { u32 config; @@ -850,6 +871,7 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BIT(CAF); /* Copy All Frames */ if (!(bp->dev->flags & IFF_BROADCAST)) config |= MACB_BIT(NBC); /* No BroadCast */ + config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); /* Initialize TX and RX buffers */ @@ -1276,6 +1298,7 @@ static int __init macb_probe(struct platform_device *pdev) /* Set MII management clock divider */ config = macb_mdc_clk_div(bp); + config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); macb_get_hwaddr(bp); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 1367b92edb3d..71424aae9c50 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -69,6 +69,13 @@ #define GEM_SA1B 0x0088 #define GEM_SA1T 0x008C #define GEM_OTX 0x0100 +#define GEM_DCFG1 0x0280 +#define GEM_DCFG2 0x0284 +#define GEM_DCFG3 0x0288 +#define GEM_DCFG4 0x028c +#define GEM_DCFG5 0x0290 +#define GEM_DCFG6 0x0294 +#define GEM_DCFG7 0x0298 /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 @@ -139,6 +146,14 @@ /* GEM specific NCFGR bitfields. */ #define GEM_CLK_OFFSET 18 #define GEM_CLK_SIZE 3 +#define GEM_DBW_OFFSET 21 +#define GEM_DBW_SIZE 2 + +/* Constants for data bus width. */ +#define GEM_DBW32 0 +#define GEM_DBW64 1 +#define GEM_DBW128 2 + /* Bitfields in NSR */ #define MACB_NSR_LINK_OFFSET 0 #define MACB_NSR_LINK_SIZE 1 @@ -247,6 +262,10 @@ #define MACB_REV_OFFSET 0 #define MACB_REV_SIZE 16 +/* Bitfields in DCFG1. */ +#define GEM_DBWDEF_OFFSET 25 +#define GEM_DBWDEF_SIZE 3 + /* Constants for CLK */ #define MACB_CLK_DIV8 0 #define MACB_CLK_DIV16 1 -- cgit v1.2.1 From 0116da4fcc1ae8a80d9002441e98768f2a6fa2fe Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Mon, 14 Mar 2011 17:38:30 +0000 Subject: macb: allow GEM to have configurable receive buffer size GEM has configurable receive buffer sizes so requires this to be programmed up. Any size < 2048 and a multiple of 64 bytes is permitted. Signed-off-by: Jamie Iles Acked-by: David S. Miller Acked-by: Nicolas Ferre Tested-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/net/ethernet/cadence/macb.c | 17 +++++++++++++++++ drivers/net/ethernet/cadence/macb.h | 5 +++++ 2 files changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 38f1932013d1..64d61461bdc7 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -856,6 +856,21 @@ static u32 macb_dbw(struct macb *bp) } } +/* + * Configure the receive DMA engine to use the correct receive buffer size. + * This is a configurable parameter for GEM. + */ +static void macb_configure_dma(struct macb *bp) +{ + u32 dmacfg; + + if (macb_is_gem(bp)) { + dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); + dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64); + gem_writel(bp, DMACFG, dmacfg); + } +} + static void macb_init_hw(struct macb *bp) { u32 config; @@ -874,6 +889,8 @@ static void macb_init_hw(struct macb *bp) config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); + macb_configure_dma(bp); + /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, bp->rx_ring_dma); macb_writel(bp, TBQP, bp->tx_ring_dma); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 71424aae9c50..193107884a5a 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -64,6 +64,7 @@ /* GEM register offsets. */ #define GEM_NCFGR 0x0004 #define GEM_USRIO 0x000c +#define GEM_DMACFG 0x0010 #define GEM_HRB 0x0080 #define GEM_HRT 0x0084 #define GEM_SA1B 0x0088 @@ -154,6 +155,10 @@ #define GEM_DBW64 1 #define GEM_DBW128 2 +/* Bitfields in DMACFG. */ +#define GEM_RXBS_OFFSET 16 +#define GEM_RXBS_SIZE 8 + /* Bitfields in NSR */ #define MACB_NSR_LINK_OFFSET 0 #define MACB_NSR_LINK_SIZE 1 -- cgit v1.2.1 From fb97a8466522f8f35ab886f7af8eefefa0a4905e Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 18 Nov 2011 15:29:25 +0100 Subject: net/macb: add DT support for Cadence macb/gem driver Allow the device tree to provide the mac address and the phy mode. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD [nicolas.ferre@atmel.com: change "compatible" node property, doc and DT hwaddr] Signed-off-by: Nicolas Ferre [jamie@jamieiles.com: add "gem" compatibility strings and doc] Acked-by: Jamie Iles Acked-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 73 +++++++++++++++++++++++++++++++++---- drivers/net/ethernet/cadence/macb.h | 2 + 2 files changed, 67 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 64d61461bdc7..baf1a0d88d8a 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "macb.h" @@ -191,7 +193,6 @@ static int macb_mii_probe(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct phy_device *phydev; - struct macb_platform_data *pdata; int ret; phydev = phy_find_first(bp->mii_bus); @@ -200,14 +201,11 @@ static int macb_mii_probe(struct net_device *dev) return -1; } - pdata = bp->pdev->dev.platform_data; /* TODO : add pin_irq */ /* attach the mac to the phy */ ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0, - pdata && pdata->is_rmii ? - PHY_INTERFACE_MODE_RMII : - PHY_INTERFACE_MODE_MII); + bp->phy_interface); if (ret) { netdev_err(dev, "Could not attach to PHY\n"); return ret; @@ -1244,6 +1242,52 @@ static const struct net_device_ops macb_netdev_ops = { #endif }; +#if defined(CONFIG_OF) +static const struct of_device_id macb_dt_ids[] = { + { .compatible = "cdns,at32ap7000-macb" }, + { .compatible = "cdns,at91sam9260-macb" }, + { .compatible = "cdns,macb" }, + { .compatible = "cdns,pc302-gem" }, + { .compatible = "cdns,gem" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, macb_dt_ids); + +static int __devinit macb_get_phy_mode_dt(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + if (np) + return of_get_phy_mode(np); + + return -ENODEV; +} + +static int __devinit macb_get_hwaddr_dt(struct macb *bp) +{ + struct device_node *np = bp->pdev->dev.of_node; + if (np) { + const char *mac = of_get_mac_address(np); + if (mac) { + memcpy(bp->dev->dev_addr, mac, ETH_ALEN); + return 0; + } + } + + return -ENODEV; +} +#else +static int __devinit macb_get_phy_mode_dt(struct platform_device *pdev) +{ + return -ENODEV; +} +static int __devinit macb_get_hwaddr_dt(struct macb *bp) +{ + return -ENODEV; +} +#endif + static int __init macb_probe(struct platform_device *pdev) { struct macb_platform_data *pdata; @@ -1318,10 +1362,22 @@ static int __init macb_probe(struct platform_device *pdev) config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); - macb_get_hwaddr(bp); - pdata = pdev->dev.platform_data; + err = macb_get_hwaddr_dt(bp); + if (err < 0) + macb_get_hwaddr(bp); + + err = macb_get_phy_mode_dt(pdev); + if (err < 0) { + pdata = pdev->dev.platform_data; + if (pdata && pdata->is_rmii) + bp->phy_interface = PHY_INTERFACE_MODE_RMII; + else + bp->phy_interface = PHY_INTERFACE_MODE_MII; + } else { + bp->phy_interface = err; + } - if (pdata && pdata->is_rmii) + if (bp->phy_interface == PHY_INTERFACE_MODE_RMII) #if defined(CONFIG_ARCH_AT91) macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN))); @@ -1444,6 +1500,7 @@ static struct platform_driver macb_driver = { .driver = { .name = "macb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(macb_dt_ids), }, }; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 193107884a5a..335e288f5314 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -532,6 +532,8 @@ struct macb { unsigned int link; unsigned int speed; unsigned int duplex; + + phy_interface_t phy_interface; }; static inline bool macb_is_gem(struct macb *bp) -- cgit v1.2.1 From 2839038bb1a72ed7ef3c39521e0ca981c9cb1534 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 24 Nov 2011 22:21:14 +0100 Subject: net/at91_ether: use gpio_is_valid for phy IRQ line Use the generic gpiolib gpio_is_valid() function to test if the phy IRQ line GPIO is actually provided. For non-connected or non-existing phy IRQ lines, -EINVAL value is used for phy_irq_pin field of struct at91_eth_data. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: David S. Miller --- drivers/net/ethernet/cadence/at91_ether.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c index dfeb46cb3f74..1a5b6efa0120 100644 --- a/drivers/net/ethernet/cadence/at91_ether.c +++ b/drivers/net/ethernet/cadence/at91_ether.c @@ -256,8 +256,7 @@ static void enable_phyirq(struct net_device *dev) unsigned int dsintr, irq_number; int status; - irq_number = lp->board_data.phy_irq_pin; - if (!irq_number) { + if (!gpio_is_valid(lp->board_data.phy_irq_pin)) { /* * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), * or board does not have it connected. @@ -266,6 +265,7 @@ static void enable_phyirq(struct net_device *dev) return; } + irq_number = lp->board_data.phy_irq_pin; status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); if (status) { printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); @@ -320,8 +320,7 @@ static void disable_phyirq(struct net_device *dev) unsigned int dsintr; unsigned int irq_number; - irq_number = lp->board_data.phy_irq_pin; - if (!irq_number) { + if (!gpio_is_valid(lp->board_data.phy_irq_pin)) { del_timer_sync(&lp->check_timer); return; } @@ -366,6 +365,7 @@ static void disable_phyirq(struct net_device *dev) disable_mdi(); spin_unlock_irq(&lp->lock); + irq_number = lp->board_data.phy_irq_pin; free_irq(irq_number, dev); /* Free interrupt handler */ } @@ -1078,7 +1078,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add netif_carrier_off(dev); /* will be enabled in open() */ /* If board has no PHY IRQ, use a timer to poll the PHY */ - if (!lp->board_data.phy_irq_pin) { + if (!gpio_is_valid(lp->board_data.phy_irq_pin)) { init_timer(&lp->check_timer); lp->check_timer.data = (unsigned long)dev; lp->check_timer.function = at91ether_check_link; @@ -1170,7 +1170,8 @@ static int __devexit at91ether_remove(struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); struct at91_private *lp = netdev_priv(dev); - if (lp->board_data.phy_irq_pin >= 32) + if (gpio_is_valid(lp->board_data.phy_irq_pin) && + lp->board_data.phy_irq_pin >= 32) gpio_free(lp->board_data.phy_irq_pin); unregister_netdev(dev); @@ -1189,11 +1190,12 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg) { struct net_device *net_dev = platform_get_drvdata(pdev); struct at91_private *lp = netdev_priv(net_dev); - int phy_irq = lp->board_data.phy_irq_pin; if (netif_running(net_dev)) { - if (phy_irq) + if (gpio_is_valid(lp->board_data.phy_irq_pin)) { + int phy_irq = lp->board_data.phy_irq_pin; disable_irq(phy_irq); + } netif_stop_queue(net_dev); netif_device_detach(net_dev); @@ -1207,7 +1209,6 @@ static int at91ether_resume(struct platform_device *pdev) { struct net_device *net_dev = platform_get_drvdata(pdev); struct at91_private *lp = netdev_priv(net_dev); - int phy_irq = lp->board_data.phy_irq_pin; if (netif_running(net_dev)) { clk_enable(lp->ether_clk); @@ -1215,8 +1216,10 @@ static int at91ether_resume(struct platform_device *pdev) netif_device_attach(net_dev); netif_start_queue(net_dev); - if (phy_irq) + if (gpio_is_valid(lp->board_data.phy_irq_pin)) { + int phy_irq = lp->board_data.phy_irq_pin; enable_irq(phy_irq); + } } return 0; } -- cgit v1.2.1 From b17471f5d121a53be1ccf6e0b0599441e56b468c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 20 Dec 2011 13:13:07 -0800 Subject: net: macb: fix build break with !CONFIG_OF This fixes the build of the macb driver that was broken by the DT changes: drivers/net/ethernet/cadence/macb.c:1503: error: implicit declaration of function 'of_match_ptr' drivers/net/ethernet/cadence/macb.c:1503: error: 'macb_dt_ids' undeclared here (not in a function) drivers/net/ethernet/cadence/macb.c:1503: error: initializer element is not constant drivers/net/ethernet/cadence/macb.c:1503: error: (near initialization for 'macb_driver.driver.of_match_table') Signed-off-by: Olof Johansson Acked-by: Nicolas Ferre --- drivers/net/ethernet/cadence/macb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index baf1a0d88d8a..f3d5c65d99cf 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include -- cgit v1.2.1