Merge branch 'bcmgenet-add-support-for-GENETv5'

Doug Berger says:

====================
net: bcmgenet: add support for GENETv5

This collection of patches contains changes related to adding
support for the BCM7260, BCM7268, and BCM7271 devices that
contain a new version of the GENET MAC IP block (v5) and a new
fast ethernet (10/100BASE-T) internal PHY.

These patches were originally developed on top of the bug fixes
of the "[PATCH v2 net 0/8] net: bcmgenet: minor bug fixes" patch
set previously accepted into the net repository, but this
submission is designed to be applied to the current net-next
that does not yet include them. As a result there will be some
merge conflicts that I would be happy to help resolve if desired.

Specifically, conflicts should occur with these patches from the
minor bug fixes set:
[PATCH v2 net 3/8] net: bcmgenet: reserved phy revisions must be checked first
[PATCH v2 net 5/8] net: bcmgenet: synchronize irq0 status between the isr and task
[PATCH v2 net 8/8] net: bcmgenet: decouple flow control from bcmgenet_tx_reclaim
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-03-13 21:51:51 -07:00
commit 62a9fa01ad
10 changed files with 407 additions and 147 deletions

View File

@ -2,11 +2,14 @@
Required properties:
- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
"brcm,genet-v3", "brcm,genet-v4".
"brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5".
- reg: address and length of the register set for the device
- interrupts: must be two cells, the first cell is the general purpose
interrupt line, while the second cell is the interrupt for the ring
RX and TX queues operating in ring mode
- interrupts and/or interrupts-extended: must be two cells, the first cell
is the general purpose interrupt line, while the second cell is the
interrupt for the ring RX and TX queues operating in ring mode. An
optional third interrupt cell for Wake-on-LAN can be specified.
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
for information on the property specifics.
- phy-mode: see ethernet.txt file in the same directory
- #address-cells: should be 1
- #size-cells: should be 1
@ -29,15 +32,15 @@ Optional properties:
Required child nodes:
- mdio bus node: this node should always be present regarless of the PHY
- mdio bus node: this node should always be present regardless of the PHY
configuration of the GENET instance
MDIO bus node required properties:
- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
parent node compatible property (e.g: brcm,genet-v4 pairs with
brcm,genet-mdio-v4)
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5", the version
has to match the parent node compatible property (e.g: brcm,genet-v4 pairs
with brcm,genet-mdio-v4)
- reg: address and length relative to the parent node base register address
- #address-cells: address cell for MDIO bus addressing, should be 1
- #size-cells: size of the cells for MDIO bus addressing, should be 0

View File

@ -2,8 +2,9 @@
Required properties:
- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
- reg: address and length of the regsiter set for the device, first one is the
"brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5" or
"brcm,unimac-mdio"
- reg: address and length of the register set for the device, first one is the
base register, and the second one is optional and for indirect accesses to
larger than 16-bits MDIO transactions
- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"

View File

@ -1,7 +1,7 @@
/*
* Broadcom GENET (Gigabit Ethernet) controller driver
*
* Copyright (c) 2014 Broadcom Corporation
* Copyright (c) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -605,7 +605,7 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
/* GENET TDMA hardware does not support a configurable timeout, but will
* always generate an interrupt either after MBDONE packets have been
* transmitted, or when the ring is emtpy.
* transmitted, or when the ring is empty.
*/
if (ec->tx_coalesce_usecs || ec->tx_coalesce_usecs_high ||
ec->tx_coalesce_usecs_irq || ec->tx_coalesce_usecs_low)
@ -1011,8 +1011,17 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv,
/* Power down LED */
if (priv->hw_params->flags & GENET_HAS_EXT) {
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= (EXT_PWR_DOWN_PHY |
EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
if (GENET_IS_V5(priv))
reg |= EXT_PWR_DOWN_PHY_EN |
EXT_PWR_DOWN_PHY_RD |
EXT_PWR_DOWN_PHY_SD |
EXT_PWR_DOWN_PHY_RX |
EXT_PWR_DOWN_PHY_TX |
EXT_IDDQ_GLBL_PWR;
else
reg |= EXT_PWR_DOWN_PHY;
reg |= (EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
bcmgenet_phy_power_set(priv->dev, false);
@ -1037,12 +1046,34 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
switch (mode) {
case GENET_POWER_PASSIVE:
reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_PHY |
EXT_PWR_DOWN_BIAS);
/* fallthrough */
reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
if (GENET_IS_V5(priv)) {
reg &= ~(EXT_PWR_DOWN_PHY_EN |
EXT_PWR_DOWN_PHY_RD |
EXT_PWR_DOWN_PHY_SD |
EXT_PWR_DOWN_PHY_RX |
EXT_PWR_DOWN_PHY_TX |
EXT_IDDQ_GLBL_PWR);
reg |= EXT_PHY_RESET;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
mdelay(1);
reg &= ~EXT_PHY_RESET;
} else {
reg &= ~EXT_PWR_DOWN_PHY;
reg |= EXT_PWR_DN_EN_LD;
}
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
bcmgenet_phy_power_set(priv->dev, true);
bcmgenet_mii_reset(priv->dev);
break;
case GENET_POWER_CABLE_SENSE:
/* enable APD */
reg |= EXT_PWR_DN_EN_LD;
if (!GENET_IS_V5(priv)) {
reg |= EXT_PWR_DN_EN_LD;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
}
break;
case GENET_POWER_WOL_MAGIC:
bcmgenet_wol_power_up_cfg(priv, mode);
@ -1050,39 +1081,20 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
default:
break;
}
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
if (mode == GENET_POWER_PASSIVE) {
bcmgenet_phy_power_set(priv->dev, true);
bcmgenet_mii_reset(priv->dev);
}
}
/* ioctl handle special commands that are not present in ethtool. */
static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
int val = 0;
if (!netif_running(dev))
return -EINVAL;
switch (cmd) {
case SIOCGMIIPHY:
case SIOCGMIIREG:
case SIOCSMIIREG:
if (!priv->phydev)
val = -ENODEV;
else
val = phy_mii_ioctl(priv->phydev, rq, cmd);
break;
if (!priv->phydev)
return -ENODEV;
default:
val = -EINVAL;
break;
}
return val;
return phy_mii_ioctl(priv->phydev, rq, cmd);
}
static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
@ -1174,14 +1186,18 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
unsigned int txbds_ready;
unsigned int txbds_processed = 0;
/* Compute how many buffers are transmitted since last xmit call */
c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
c_index &= DMA_C_INDEX_MASK;
if (likely(c_index >= ring->c_index))
txbds_ready = c_index - ring->c_index;
/* Clear status before servicing to reduce spurious interrupts */
if (ring->index == DESC_INDEX)
bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE,
INTRL2_CPU_CLEAR);
else
txbds_ready = (DMA_C_INDEX_MASK + 1) - ring->c_index + c_index;
bcmgenet_intrl2_1_writel(priv, (1 << ring->index),
INTRL2_CPU_CLEAR);
/* Compute how many buffers are transmitted since last xmit call */
c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX)
& DMA_C_INDEX_MASK;
txbds_ready = (c_index - ring->c_index) & DMA_C_INDEX_MASK;
netif_dbg(priv, tx_done, dev,
"%s ring=%d old_c_index=%u c_index=%u txbds_ready=%u\n",
@ -1214,7 +1230,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
}
ring->free_bds += txbds_processed;
ring->c_index = (ring->c_index + txbds_processed) & DMA_C_INDEX_MASK;
ring->c_index = c_index;
dev->stats.tx_packets += pkts_compl;
dev->stats.tx_bytes += bytes_compl;
@ -1227,7 +1243,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
netif_tx_wake_queue(txq);
}
return pkts_compl;
return txbds_processed;
}
static unsigned int bcmgenet_tx_reclaim(struct net_device *dev,
@ -1588,10 +1604,21 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
unsigned long dma_flag;
int len;
unsigned int rxpktprocessed = 0, rxpkttoprocess;
unsigned int p_index;
unsigned int p_index, mask;
unsigned int discards;
unsigned int chksum_ok = 0;
/* Clear status before servicing to reduce spurious interrupts */
if (ring->index == DESC_INDEX) {
bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE,
INTRL2_CPU_CLEAR);
} else {
mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index);
bcmgenet_intrl2_1_writel(priv,
mask,
INTRL2_CPU_CLEAR);
}
p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX);
discards = (p_index >> DMA_P_INDEX_DISCARD_CNT_SHIFT) &
@ -1611,12 +1638,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
}
p_index &= DMA_P_INDEX_MASK;
if (likely(p_index >= ring->c_index))
rxpkttoprocess = p_index - ring->c_index;
else
rxpkttoprocess = (DMA_C_INDEX_MASK + 1) - ring->c_index +
p_index;
rxpkttoprocess = (p_index - ring->c_index) & DMA_C_INDEX_MASK;
netif_dbg(priv, rx_status, dev,
"RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
@ -1843,10 +1865,8 @@ static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
/* Mask all interrupts.*/
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
}
static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)
@ -1873,8 +1893,6 @@ static int init_umac(struct bcmgenet_priv *priv)
int ret;
u32 reg;
u32 int0_enable = 0;
u32 int1_enable = 0;
int i;
dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
@ -1901,12 +1919,6 @@ static int init_umac(struct bcmgenet_priv *priv)
bcmgenet_intr_disable(priv);
/* Enable Rx default queue 16 interrupts */
int0_enable |= UMAC_IRQ_RXDMA_DONE;
/* Enable Tx default queue 16 interrupts */
int0_enable |= UMAC_IRQ_TXDMA_DONE;
/* Configure backpressure vectors for MoCA */
if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
reg = bcmgenet_bp_mc_get(priv);
@ -1924,18 +1936,8 @@ static int init_umac(struct bcmgenet_priv *priv)
if (priv->hw_params->flags & GENET_HAS_MDIO_INTR)
int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
/* Enable Rx priority queue interrupts */
for (i = 0; i < priv->hw_params->rx_queues; ++i)
int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
/* Enable Tx priority queue interrupts */
for (i = 0; i < priv->hw_params->tx_queues; ++i)
int1_enable |= (1 << i);
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
/* Enable rx/tx engine.*/
dev_dbg(kdev, "done init umac\n");
return 0;
@ -2067,22 +2069,33 @@ static void bcmgenet_init_tx_napi(struct bcmgenet_priv *priv)
static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv)
{
unsigned int i;
u32 int0_enable = UMAC_IRQ_TXDMA_DONE;
u32 int1_enable = 0;
struct bcmgenet_tx_ring *ring;
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
ring = &priv->tx_rings[i];
napi_enable(&ring->napi);
int1_enable |= (1 << i);
}
ring = &priv->tx_rings[DESC_INDEX];
napi_enable(&ring->napi);
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
}
static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv)
{
unsigned int i;
u32 int0_disable = UMAC_IRQ_TXDMA_DONE;
u32 int1_disable = 0xffff;
struct bcmgenet_tx_ring *ring;
bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
for (i = 0; i < priv->hw_params->tx_queues; ++i) {
ring = &priv->tx_rings[i];
napi_disable(&ring->napi);
@ -2195,22 +2208,33 @@ static void bcmgenet_init_rx_napi(struct bcmgenet_priv *priv)
static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv)
{
unsigned int i;
u32 int0_enable = UMAC_IRQ_RXDMA_DONE;
u32 int1_enable = 0;
struct bcmgenet_rx_ring *ring;
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
ring = &priv->rx_rings[i];
napi_enable(&ring->napi);
int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));
}
ring = &priv->rx_rings[DESC_INDEX];
napi_enable(&ring->napi);
bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR);
bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR);
}
static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv)
{
unsigned int i;
u32 int0_disable = UMAC_IRQ_RXDMA_DONE;
u32 int1_disable = 0xffff << UMAC_IRQ1_RX_INTR_SHIFT;
struct bcmgenet_rx_ring *ring;
bcmgenet_intrl2_0_writel(priv, int0_disable, INTRL2_CPU_MASK_SET);
bcmgenet_intrl2_1_writel(priv, int1_disable, INTRL2_CPU_MASK_SET);
for (i = 0; i < priv->hw_params->rx_queues; ++i) {
ring = &priv->rx_rings[i];
napi_disable(&ring->napi);
@ -2462,13 +2486,6 @@ static void bcmgenet_irq_task(struct work_struct *work)
netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
if (priv->irq0_stat & UMAC_IRQ_MPD_R) {
priv->irq0_stat &= ~UMAC_IRQ_MPD_R;
netif_dbg(priv, wol, priv->dev,
"magic packet detected, waking up\n");
bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
}
/* Link UP/DOWN event */
if (priv->irq0_stat & UMAC_IRQ_LINK_EVENT) {
phy_mac_interrupt(priv->phydev,
@ -2565,8 +2582,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
UMAC_IRQ_PHY_DET_F |
UMAC_IRQ_LINK_EVENT |
UMAC_IRQ_HFB_SM |
UMAC_IRQ_HFB_MM |
UMAC_IRQ_MPD_R)) {
UMAC_IRQ_HFB_MM)) {
/* all other interested interrupts handled in bottom half */
schedule_work(&priv->bcmgenet_irq_work);
}
@ -2845,7 +2861,7 @@ static int bcmgenet_close(struct net_device *dev)
if (ret)
return ret;
/* Disable MAC transmit. TX DMA disabled have to done before this */
/* Disable MAC transmit. TX DMA disabled must be done before this */
umac_enable_set(priv, CMD_TX_EN, false);
/* tx reclaim */
@ -3110,6 +3126,25 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
.flags = GENET_HAS_40BITS | GENET_HAS_EXT |
GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET,
},
[GENET_V5] = {
.tx_queues = 4,
.tx_bds_per_q = 32,
.rx_queues = 0,
.rx_bds_per_q = 0,
.bp_in_en_shift = 17,
.bp_in_mask = 0x1ffff,
.hfb_filter_cnt = 48,
.hfb_filter_size = 128,
.qtag_mask = 0x3F,
.tbuf_offset = 0x0600,
.hfb_offset = 0x8000,
.hfb_reg_offset = 0xfc00,
.rdma_offset = 0x2000,
.tdma_offset = 0x4000,
.words_per_bd = 3,
.flags = GENET_HAS_40BITS | GENET_HAS_EXT |
GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET,
},
};
/* Infer hardware parameters from the detected GENET version */
@ -3120,26 +3155,22 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
u8 major;
u16 gphy_rev;
if (GENET_IS_V4(priv)) {
if (GENET_IS_V5(priv) || GENET_IS_V4(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
genet_dma_ring_regs = genet_dma_ring_regs_v4;
priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
priv->version = GENET_V4;
} else if (GENET_IS_V3(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
genet_dma_ring_regs = genet_dma_ring_regs_v123;
priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
priv->version = GENET_V3;
} else if (GENET_IS_V2(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v2;
genet_dma_ring_regs = genet_dma_ring_regs_v123;
priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
priv->version = GENET_V2;
} else if (GENET_IS_V1(priv)) {
bcmgenet_dma_regs = bcmgenet_dma_regs_v1;
genet_dma_ring_regs = genet_dma_ring_regs_v123;
priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
priv->version = GENET_V1;
}
/* enum genet_version starts at 1 */
@ -3149,7 +3180,9 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
/* Read GENET HW version */
reg = bcmgenet_sys_readl(priv, SYS_REV_CTRL);
major = (reg >> 24 & 0x0f);
if (major == 5)
if (major == 6)
major = 5;
else if (major == 5)
major = 4;
else if (major == 0)
major = 1;
@ -3177,16 +3210,22 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
*/
gphy_rev = reg & 0xffff;
if (GENET_IS_V5(priv)) {
/* The EPHY revision should come from the MDIO registers of
* the PHY not from GENET.
*/
if (gphy_rev != 0) {
pr_warn("GENET is reporting EPHY revision: 0x%04x\n",
gphy_rev);
}
/* This is the good old scheme, just GPHY major, no minor nor patch */
if ((gphy_rev & 0xf0) != 0)
} else if ((gphy_rev & 0xf0) != 0) {
priv->gphy_rev = gphy_rev << 8;
/* This is the new scheme, GPHY major rolls over with 0x10 = rev G0 */
else if ((gphy_rev & 0xff00) != 0)
} else if ((gphy_rev & 0xff00) != 0) {
priv->gphy_rev = gphy_rev;
/* This is reserved so should require special treatment */
else if (gphy_rev == 0 || gphy_rev == 0x01ff) {
} else if (gphy_rev == 0 || gphy_rev == 0x01ff) {
pr_warn("Invalid GPHY revision detected: 0x%04x\n", gphy_rev);
return;
}
@ -3219,6 +3258,7 @@ static const struct of_device_id bcmgenet_match[] = {
{ .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 },
{ .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 },
{ .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 },
{ .compatible = "brcm,genet-v5", .data = (void *)GENET_V5 },
{ },
};
MODULE_DEVICE_TABLE(of, bcmgenet_match);
@ -3406,7 +3446,7 @@ static int bcmgenet_suspend(struct device *d)
if (ret)
return ret;
/* Disable MAC transmit. TX DMA disabled have to done before this */
/* Disable MAC transmit. TX DMA disabled must be done before this */
umac_enable_set(priv, CMD_TX_EN, false);
/* tx reclaim */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014 Broadcom Corporation
* Copyright (c) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -351,8 +351,14 @@ struct bcmgenet_mib_counters {
#define EXT_PWR_DN_EN_LD (1 << 3)
#define EXT_ENERGY_DET (1 << 4)
#define EXT_IDDQ_FROM_PHY (1 << 5)
#define EXT_IDDQ_GLBL_PWR (1 << 7)
#define EXT_PHY_RESET (1 << 8)
#define EXT_ENERGY_DET_MASK (1 << 12)
#define EXT_PWR_DOWN_PHY_TX (1 << 16)
#define EXT_PWR_DOWN_PHY_RX (1 << 17)
#define EXT_PWR_DOWN_PHY_SD (1 << 18)
#define EXT_PWR_DOWN_PHY_RD (1 << 19)
#define EXT_PWR_DOWN_PHY_EN (1 << 20)
#define EXT_RGMII_OOB_CTRL 0x0C
#define RGMII_LINK (1 << 4)
@ -495,13 +501,15 @@ enum bcmgenet_version {
GENET_V1 = 1,
GENET_V2,
GENET_V3,
GENET_V4
GENET_V4,
GENET_V5
};
#define GENET_IS_V1(p) ((p)->version == GENET_V1)
#define GENET_IS_V2(p) ((p)->version == GENET_V2)
#define GENET_IS_V3(p) ((p)->version == GENET_V3)
#define GENET_IS_V4(p) ((p)->version == GENET_V4)
#define GENET_IS_V5(p) ((p)->version == GENET_V5)
/* Hardware flags */
#define GENET_HAS_40BITS (1 << 0)

View File

@ -1,7 +1,7 @@
/*
* Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
*
* Copyright (c) 2014 Broadcom Corporation
* Copyright (c) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -127,7 +127,6 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode)
{
struct net_device *dev = priv->dev;
u32 cpu_mask_clear;
int retries = 0;
u32 reg;
@ -173,18 +172,12 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
}
/* Enable the MPD interrupt */
cpu_mask_clear = UMAC_IRQ_MPD_R;
bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR);
return 0;
}
void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode)
{
u32 cpu_mask_set;
u32 reg;
if (mode != GENET_POWER_WOL_MAGIC) {
@ -201,10 +194,4 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
reg &= ~CMD_CRC_FWD;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
priv->crc_fwd_en = 0;
/* Stop monitoring magic packet IRQ */
cpu_mask_set = UMAC_IRQ_MPD_R;
/* Stop monitoring magic packet IRQ */
bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET);
}

View File

@ -1,7 +1,7 @@
/*
* Broadcom GENET MDIO routines
*
* Copyright (c) 2014 Broadcom Corporation
* Copyright (c) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -195,29 +195,31 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
u32 reg = 0;
/* EXT_GPHY_CTRL is only valid for GENETv4 and onward */
if (!GENET_IS_V4(priv))
return;
if (GENET_IS_V4(priv)) {
reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
if (enable) {
reg &= ~EXT_CK25_DIS;
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
if (enable) {
reg &= ~EXT_CK25_DIS;
reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
reg |= EXT_GPHY_RESET;
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
reg &= ~EXT_GPHY_RESET;
} else {
reg |= EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN |
EXT_GPHY_RESET;
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
reg |= EXT_CK25_DIS;
}
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
reg |= EXT_GPHY_RESET;
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
reg &= ~EXT_GPHY_RESET;
udelay(60);
} else {
reg |= EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN | EXT_GPHY_RESET;
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
mdelay(1);
reg |= EXT_CK25_DIS;
}
bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
udelay(60);
}
static void bcmgenet_internal_phy_setup(struct net_device *dev)
@ -227,10 +229,12 @@ static void bcmgenet_internal_phy_setup(struct net_device *dev)
/* Power up PHY */
bcmgenet_phy_power_set(dev, true);
/* enable APD */
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= EXT_PWR_DN_EN_LD;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
if (!GENET_IS_V5(priv)) {
/* enable APD */
reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
reg |= EXT_PWR_DN_EN_LD;
bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
}
bcmgenet_mii_reset(dev);
}
@ -238,10 +242,12 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
{
u32 reg;
/* Speed settings are set in bcmgenet_mii_setup() */
reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
reg |= LED_ACT_SOURCE_MAC;
bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
if (!GENET_IS_V5(priv)) {
/* Speed settings are set in bcmgenet_mii_setup() */
reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
reg |= LED_ACT_SOURCE_MAC;
bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
}
if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET)
fixed_phy_set_link_update(priv->phydev,

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Broadcom Corporation
* Copyright (C) 2015-2017 Broadcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -221,9 +221,9 @@ int bcm_phy_set_eee(struct phy_device *phydev, bool enable)
return val;
if (enable)
val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
val |= (MDIO_EEE_100TX | MDIO_EEE_1000T);
else
val &= ~(MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
val &= ~(MDIO_EEE_100TX | MDIO_EEE_1000T);
phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
MDIO_MMD_AN, (u32)val);

View File

@ -1,7 +1,7 @@
/*
* Broadcom BCM7xxx internal transceivers support.
*
* Copyright (C) 2014, Broadcom Corporation
* Copyright (C) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -19,7 +19,7 @@
/* Broadcom BCM7xxx internal PHY registers */
/* 40nm only register definitions */
/* EPHY only register definitions */
#define MII_BCM7XXX_100TX_AUX_CTL 0x10
#define MII_BCM7XXX_100TX_FALSE_CAR 0x13
#define MII_BCM7XXX_100TX_DISC 0x14
@ -27,6 +27,19 @@
#define MII_BCM7XXX_64CLK_MDIO BIT(12)
#define MII_BCM7XXX_TEST 0x1f
#define MII_BCM7XXX_SHD_MODE_2 BIT(2)
#define MII_BCM7XXX_SHD_2_ADDR_CTRL 0xe
#define MII_BCM7XXX_SHD_2_CTRL_STAT 0xf
#define MII_BCM7XXX_SHD_2_BIAS_TRIM 0x1a
#define MII_BCM7XXX_SHD_3_AN_EEE_ADV 0x3
#define MII_BCM7XXX_SHD_3_PCS_CTRL_2 0x6
#define MII_BCM7XXX_PCS_CTRL_2_DEF 0x4400
#define MII_BCM7XXX_SHD_3_AN_STAT 0xb
#define MII_BCM7XXX_AN_NULL_MSG_EN BIT(0)
#define MII_BCM7XXX_AN_EEE_EN BIT(1)
#define MII_BCM7XXX_SHD_3_EEE_THRESH 0xe
#define MII_BCM7XXX_EEE_THRESH_DEF 0x50
#define MII_BCM7XXX_SHD_3_TL4 0x23
#define MII_BCM7XXX_TL4_RST_MSK (BIT(2) | BIT(1))
/* 28nm only register definitions */
#define MISC_ADDR(base, channel) base, channel
@ -286,6 +299,181 @@ static int phy_set_clr_bits(struct phy_device *dev, int location,
return v;
}
static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
{
int ret;
/* set shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
MII_BCM7XXX_SHD_MODE_2, 0);
if (ret < 0)
return ret;
/* Set current trim values INT_trim = -1, Ext_trim =0 */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0);
if (ret < 0)
goto reset_shadow_mode;
/* Cal reset */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_TL4);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MII_BCM7XXX_TL4_RST_MSK, 0);
if (ret < 0)
goto reset_shadow_mode;
/* Cal reset disable */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_TL4);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
0, MII_BCM7XXX_TL4_RST_MSK);
if (ret < 0)
goto reset_shadow_mode;
reset_shadow_mode:
/* reset shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
MII_BCM7XXX_SHD_MODE_2);
if (ret < 0)
return ret;
return 0;
}
/* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */
static int bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev)
{
int ret;
/* set shadow mode 1 */
ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST,
MII_BRCM_FET_BT_SRE, 0);
if (ret < 0)
return ret;
/* Enable auto-power down */
ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
MII_BRCM_FET_SHDW_AS2_APDE, 0);
if (ret < 0)
return ret;
/* reset shadow mode 1 */
ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
MII_BRCM_FET_BT_SRE);
if (ret < 0)
return ret;
return 0;
}
static int bcm7xxx_28nm_ephy_eee_enable(struct phy_device *phydev)
{
int ret;
/* set shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
MII_BCM7XXX_SHD_MODE_2, 0);
if (ret < 0)
return ret;
/* Advertise supported modes */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_AN_EEE_ADV);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MDIO_EEE_100TX);
if (ret < 0)
goto reset_shadow_mode;
/* Restore Defaults */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_PCS_CTRL_2);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MII_BCM7XXX_PCS_CTRL_2_DEF);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_EEE_THRESH);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MII_BCM7XXX_EEE_THRESH_DEF);
if (ret < 0)
goto reset_shadow_mode;
/* Enable EEE autonegotiation */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_AN_STAT);
if (ret < 0)
goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
(MII_BCM7XXX_AN_NULL_MSG_EN | MII_BCM7XXX_AN_EEE_EN));
if (ret < 0)
goto reset_shadow_mode;
reset_shadow_mode:
/* reset shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
MII_BCM7XXX_SHD_MODE_2);
if (ret < 0)
return ret;
/* Restart autoneg */
phy_write(phydev, MII_BMCR,
(BMCR_SPEED100 | BMCR_ANENABLE | BMCR_ANRESTART));
return 0;
}
static int bcm7xxx_28nm_ephy_config_init(struct phy_device *phydev)
{
u8 rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
int ret = 0;
pr_info_once("%s: %s PHY revision: 0x%02x\n",
phydev_name(phydev), phydev->drv->name, rev);
/* Dummy read to a register to workaround a possible issue upon reset
* where the internal inverter may not allow the first MDIO transaction
* to pass the MDIO management controller and make us return 0xffff for
* such reads.
*/
phy_read(phydev, MII_BMSR);
/* Apply AFE software work-around if necessary */
if (rev == 0x01) {
ret = bcm7xxx_28nm_ephy_01_afe_config_init(phydev);
if (ret)
return ret;
}
ret = bcm7xxx_28nm_ephy_eee_enable(phydev);
if (ret)
return ret;
return bcm7xxx_28nm_ephy_apd_enable(phydev);
}
static int bcm7xxx_28nm_ephy_resume(struct phy_device *phydev)
{
int ret;
/* Re-apply workarounds coming out suspend/resume */
ret = bcm7xxx_28nm_ephy_config_init(phydev);
if (ret)
return ret;
return genphy_config_aneg(phydev);
}
static int bcm7xxx_config_init(struct phy_device *phydev)
{
int ret;
@ -434,6 +622,23 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
.probe = bcm7xxx_28nm_probe, \
}
#define BCM7XXX_28NM_EPHY(_oui, _name) \
{ \
.phy_id = (_oui), \
.phy_id_mask = 0xfffffff0, \
.name = _name, \
.features = PHY_BASIC_FEATURES, \
.flags = PHY_IS_INTERNAL, \
.config_init = bcm7xxx_28nm_ephy_config_init, \
.config_aneg = genphy_config_aneg, \
.read_status = genphy_read_status, \
.resume = bcm7xxx_28nm_ephy_resume, \
.get_sset_count = bcm_phy_get_sset_count, \
.get_strings = bcm_phy_get_strings, \
.get_stats = bcm7xxx_28nm_get_phy_stats, \
.probe = bcm7xxx_28nm_probe, \
}
#define BCM7XXX_40NM_EPHY(_oui, _name) \
{ \
.phy_id = (_oui), \
@ -450,6 +655,9 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
static struct phy_driver bcm7xxx_driver[] = {
BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
BCM7XXX_28NM_EPHY(PHY_ID_BCM7260, "Broadcom BCM7260"),
BCM7XXX_28NM_EPHY(PHY_ID_BCM7268, "Broadcom BCM7268"),
BCM7XXX_28NM_EPHY(PHY_ID_BCM7271, "Broadcom BCM7271"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
@ -466,6 +674,9 @@ static struct phy_driver bcm7xxx_driver[] = {
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
{ PHY_ID_BCM7250, 0xfffffff0, },
{ PHY_ID_BCM7260, 0xfffffff0, },
{ PHY_ID_BCM7268, 0xfffffff0, },
{ PHY_ID_BCM7271, 0xfffffff0, },
{ PHY_ID_BCM7278, 0xfffffff0, },
{ PHY_ID_BCM7364, 0xfffffff0, },
{ PHY_ID_BCM7366, 0xfffffff0, },

View File

@ -1,7 +1,7 @@
/*
* Broadcom UniMAC MDIO bus controller driver
*
* Copyright (C) 2014, Broadcom Corporation
* Copyright (C) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -228,6 +228,7 @@ static int unimac_mdio_remove(struct platform_device *pdev)
}
static const struct of_device_id unimac_mdio_ids[] = {
{ .compatible = "brcm,genet-mdio-v5", },
{ .compatible = "brcm,genet-mdio-v4", },
{ .compatible = "brcm,genet-mdio-v3", },
{ .compatible = "brcm,genet-mdio-v2", },

View File

@ -25,6 +25,9 @@
#define PHY_ID_BCM57780 0x03625d90
#define PHY_ID_BCM7250 0xae025280
#define PHY_ID_BCM7260 0xae025190
#define PHY_ID_BCM7268 0xae025090
#define PHY_ID_BCM7271 0xae0253b0
#define PHY_ID_BCM7278 0xae0251a0
#define PHY_ID_BCM7364 0xae025260
#define PHY_ID_BCM7366 0x600d8490