Merge branch 'ARM-Enable-GENET-support-for-RPi-4'
Stefan Wahren says: ==================== ARM: Enable GENET support for RPi 4 Raspberry Pi 4 uses the broadcom genet chip in version five. This chip has a dma controller integrated. Up to now the maximal burst size was hard-coded to 0x10. But it turns out that Raspberry Pi 4 does only work with the smaller maximal burst size of 0x8. Additionally the patch series has some IRQ retrieval improvements and adds support for a missing PHY mode. This series based on Matthias Brugger's V1 series [1]. [1] - https://patchwork.kernel.org/cover/11186193/ Changes in V5: - address Doug's comment Changes in V4: - rebased on current net-next - remove RGMII_ID support - remove fixes tag from patch 1 - add Florian's suggestions to patch 5 Changes in V3: - introduce SoC-specific compatibles for GENET (incl. dt-binding) - use platform_get_irq_optional for optional IRQ - remove Fixes tag from IRQ error handling change - move most of MDIO stuff to bcm2711.dtsi Changes in V2: - add 2 fixes for IRQ retrieval - add support for missing PHY modes - declare PHY mode RGMII RXID based on the default settings - add alias to allow firmware append the MAC address ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
90bc72b13c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
|
- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
|
||||||
"brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5".
|
"brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5", "brcm,bcm2711-genet-v5".
|
||||||
- reg: address and length of the register set for the device
|
- reg: address and length of the register set for the device
|
||||||
- interrupts and/or interrupts-extended: must be two cells, the first cell
|
- interrupts and/or interrupts-extended: must be two cells, the first cell
|
||||||
is the general purpose interrupt line, while the second cell is the
|
is the general purpose interrupt line, while the second cell is the
|
||||||
|
@ -2576,7 +2576,8 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Init rDma */
|
/* Init rDma */
|
||||||
bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
|
bcmgenet_rdma_writel(priv, priv->dma_max_burst_length,
|
||||||
|
DMA_SCB_BURST_SIZE);
|
||||||
|
|
||||||
/* Initialize Rx queues */
|
/* Initialize Rx queues */
|
||||||
ret = bcmgenet_init_rx_queues(priv->dev);
|
ret = bcmgenet_init_rx_queues(priv->dev);
|
||||||
@ -2589,7 +2590,8 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Init tDma */
|
/* Init tDma */
|
||||||
bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
|
bcmgenet_tdma_writel(priv, priv->dma_max_burst_length,
|
||||||
|
DMA_SCB_BURST_SIZE);
|
||||||
|
|
||||||
/* Initialize Tx queues */
|
/* Initialize Tx queues */
|
||||||
bcmgenet_init_tx_queues(priv->dev);
|
bcmgenet_init_tx_queues(priv->dev);
|
||||||
@ -3420,12 +3422,48 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
|
|||||||
params->words_per_bd);
|
params->words_per_bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bcmgenet_plat_data {
|
||||||
|
enum bcmgenet_version version;
|
||||||
|
u32 dma_max_burst_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcmgenet_plat_data v1_plat_data = {
|
||||||
|
.version = GENET_V1,
|
||||||
|
.dma_max_burst_length = DMA_MAX_BURST_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcmgenet_plat_data v2_plat_data = {
|
||||||
|
.version = GENET_V2,
|
||||||
|
.dma_max_burst_length = DMA_MAX_BURST_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcmgenet_plat_data v3_plat_data = {
|
||||||
|
.version = GENET_V3,
|
||||||
|
.dma_max_burst_length = DMA_MAX_BURST_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcmgenet_plat_data v4_plat_data = {
|
||||||
|
.version = GENET_V4,
|
||||||
|
.dma_max_burst_length = DMA_MAX_BURST_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcmgenet_plat_data v5_plat_data = {
|
||||||
|
.version = GENET_V5,
|
||||||
|
.dma_max_burst_length = DMA_MAX_BURST_LENGTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcmgenet_plat_data bcm2711_plat_data = {
|
||||||
|
.version = GENET_V5,
|
||||||
|
.dma_max_burst_length = 0x08,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id bcmgenet_match[] = {
|
static const struct of_device_id bcmgenet_match[] = {
|
||||||
{ .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 },
|
{ .compatible = "brcm,genet-v1", .data = &v1_plat_data },
|
||||||
{ .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 },
|
{ .compatible = "brcm,genet-v2", .data = &v2_plat_data },
|
||||||
{ .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 },
|
{ .compatible = "brcm,genet-v3", .data = &v3_plat_data },
|
||||||
{ .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 },
|
{ .compatible = "brcm,genet-v4", .data = &v4_plat_data },
|
||||||
{ .compatible = "brcm,genet-v5", .data = (void *)GENET_V5 },
|
{ .compatible = "brcm,genet-v5", .data = &v5_plat_data },
|
||||||
|
{ .compatible = "brcm,bcm2711-genet-v5", .data = &bcm2711_plat_data },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, bcmgenet_match);
|
MODULE_DEVICE_TABLE(of, bcmgenet_match);
|
||||||
@ -3435,6 +3473,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
|||||||
struct bcmgenet_platform_data *pd = pdev->dev.platform_data;
|
struct bcmgenet_platform_data *pd = pdev->dev.platform_data;
|
||||||
struct device_node *dn = pdev->dev.of_node;
|
struct device_node *dn = pdev->dev.of_node;
|
||||||
const struct of_device_id *of_id = NULL;
|
const struct of_device_id *of_id = NULL;
|
||||||
|
const struct bcmgenet_plat_data *pdata;
|
||||||
struct bcmgenet_priv *priv;
|
struct bcmgenet_priv *priv;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
const void *macaddr;
|
const void *macaddr;
|
||||||
@ -3458,13 +3497,16 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
priv = netdev_priv(dev);
|
priv = netdev_priv(dev);
|
||||||
priv->irq0 = platform_get_irq(pdev, 0);
|
priv->irq0 = platform_get_irq(pdev, 0);
|
||||||
priv->irq1 = platform_get_irq(pdev, 1);
|
if (priv->irq0 < 0) {
|
||||||
priv->wol_irq = platform_get_irq(pdev, 2);
|
err = priv->irq0;
|
||||||
if (!priv->irq0 || !priv->irq1) {
|
|
||||||
dev_err(&pdev->dev, "can't find IRQs\n");
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
priv->irq1 = platform_get_irq(pdev, 1);
|
||||||
|
if (priv->irq1 < 0) {
|
||||||
|
err = priv->irq1;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
priv->wol_irq = platform_get_irq_optional(pdev, 2);
|
||||||
|
|
||||||
if (dn)
|
if (dn)
|
||||||
macaddr = of_get_mac_address(dn);
|
macaddr = of_get_mac_address(dn);
|
||||||
@ -3513,10 +3555,14 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
priv->pdev = pdev;
|
priv->pdev = pdev;
|
||||||
if (of_id)
|
if (of_id) {
|
||||||
priv->version = (enum bcmgenet_version)of_id->data;
|
pdata = of_id->data;
|
||||||
else
|
priv->version = pdata->version;
|
||||||
|
priv->dma_max_burst_length = pdata->dma_max_burst_length;
|
||||||
|
} else {
|
||||||
priv->version = pd->genet_version;
|
priv->version = pd->genet_version;
|
||||||
|
priv->dma_max_burst_length = DMA_MAX_BURST_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
|
priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
|
||||||
if (IS_ERR(priv->clk)) {
|
if (IS_ERR(priv->clk)) {
|
||||||
|
@ -664,6 +664,7 @@ struct bcmgenet_priv {
|
|||||||
bool crc_fwd_en;
|
bool crc_fwd_en;
|
||||||
|
|
||||||
unsigned int dma_rx_chk_bit;
|
unsigned int dma_rx_chk_bit;
|
||||||
|
u32 dma_max_burst_length;
|
||||||
|
|
||||||
u32 msg_enable;
|
u32 msg_enable;
|
||||||
|
|
||||||
|
@ -213,11 +213,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
|
|||||||
udelay(2);
|
udelay(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->ext_phy = !priv->internal_phy &&
|
|
||||||
(priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
|
|
||||||
|
|
||||||
switch (priv->phy_interface) {
|
switch (priv->phy_interface) {
|
||||||
case PHY_INTERFACE_MODE_INTERNAL:
|
case PHY_INTERFACE_MODE_INTERNAL:
|
||||||
|
phy_name = "internal PHY";
|
||||||
|
/* fall through */
|
||||||
case PHY_INTERFACE_MODE_MOCA:
|
case PHY_INTERFACE_MODE_MOCA:
|
||||||
/* Irrespective of the actually configured PHY speed (100 or
|
/* Irrespective of the actually configured PHY speed (100 or
|
||||||
* 1000) GENETv4 only has an internal GPHY so we will just end
|
* 1000) GENETv4 only has an internal GPHY so we will just end
|
||||||
@ -229,11 +228,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
|
|||||||
else
|
else
|
||||||
port_ctrl = PORT_MODE_INT_EPHY;
|
port_ctrl = PORT_MODE_INT_EPHY;
|
||||||
|
|
||||||
bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
|
if (!phy_name) {
|
||||||
|
|
||||||
if (priv->internal_phy) {
|
|
||||||
phy_name = "internal PHY";
|
|
||||||
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
|
|
||||||
phy_name = "MoCA";
|
phy_name = "MoCA";
|
||||||
bcmgenet_moca_phy_setup(priv);
|
bcmgenet_moca_phy_setup(priv);
|
||||||
}
|
}
|
||||||
@ -242,11 +237,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
|
|||||||
case PHY_INTERFACE_MODE_MII:
|
case PHY_INTERFACE_MODE_MII:
|
||||||
phy_name = "external MII";
|
phy_name = "external MII";
|
||||||
phy_set_max_speed(phydev, SPEED_100);
|
phy_set_max_speed(phydev, SPEED_100);
|
||||||
bcmgenet_sys_writel(priv,
|
port_ctrl = PORT_MODE_EXT_EPHY;
|
||||||
PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
|
|
||||||
/* Restore the MII PHY after isolation */
|
|
||||||
if (bmcr >= 0)
|
|
||||||
phy_write(phydev, MII_BMCR, bmcr);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PHY_INTERFACE_MODE_REVMII:
|
case PHY_INTERFACE_MODE_REVMII:
|
||||||
@ -261,31 +252,43 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
|
|||||||
port_ctrl = PORT_MODE_EXT_RVMII_50;
|
port_ctrl = PORT_MODE_EXT_RVMII_50;
|
||||||
else
|
else
|
||||||
port_ctrl = PORT_MODE_EXT_RVMII_25;
|
port_ctrl = PORT_MODE_EXT_RVMII_25;
|
||||||
bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PHY_INTERFACE_MODE_RGMII:
|
case PHY_INTERFACE_MODE_RGMII:
|
||||||
/* RGMII_NO_ID: TXC transitions at the same time as TXD
|
/* RGMII_NO_ID: TXC transitions at the same time as TXD
|
||||||
* (requires PCB or receiver-side delay)
|
* (requires PCB or receiver-side delay)
|
||||||
* RGMII: Add 2ns delay on TXC (90 degree shift)
|
|
||||||
*
|
*
|
||||||
* ID is implicitly disabled for 100Mbps (RG)MII operation.
|
* ID is implicitly disabled for 100Mbps (RG)MII operation.
|
||||||
*/
|
*/
|
||||||
|
phy_name = "external RGMII (no delay)";
|
||||||
id_mode_dis = BIT(16);
|
id_mode_dis = BIT(16);
|
||||||
/* fall through */
|
port_ctrl = PORT_MODE_EXT_GPHY;
|
||||||
|
break;
|
||||||
|
|
||||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||||
if (id_mode_dis)
|
/* RGMII_TXID: Add 2ns delay on TXC (90 degree shift) */
|
||||||
phy_name = "external RGMII (no delay)";
|
phy_name = "external RGMII (TX delay)";
|
||||||
else
|
port_ctrl = PORT_MODE_EXT_GPHY;
|
||||||
phy_name = "external RGMII (TX delay)";
|
break;
|
||||||
bcmgenet_sys_writel(priv,
|
|
||||||
PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
|
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||||
|
phy_name = "external RGMII (RX delay)";
|
||||||
|
port_ctrl = PORT_MODE_EXT_GPHY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
|
dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
|
||||||
|
|
||||||
|
/* Restore the MII PHY after isolation */
|
||||||
|
if (bmcr >= 0)
|
||||||
|
phy_write(phydev, MII_BMCR, bmcr);
|
||||||
|
|
||||||
|
priv->ext_phy = !priv->internal_phy &&
|
||||||
|
(priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
|
||||||
|
|
||||||
/* This is an external PHY (xMII), so we need to enable the RGMII
|
/* This is an external PHY (xMII), so we need to enable the RGMII
|
||||||
* block for the interface to work
|
* block for the interface to work
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user