Commit 90bc72b1 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 2eea1fa8 da388022
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@

Required properties:
- 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
- interrupts and/or interrupts-extended: must be two cells, the first cell
  is the general purpose interrupt line, while the second cell is the
+60 −14
Original line number Diff line number Diff line
@@ -2576,7 +2576,8 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
	}

	/* 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 */
	ret = bcmgenet_init_rx_queues(priv->dev);
@@ -2589,7 +2590,8 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
	}

	/* 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 */
	bcmgenet_init_tx_queues(priv->dev);
@@ -3420,12 +3422,48 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
		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[] = {
	{ .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 },
	{ .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 },
	{ .compatible = "brcm,genet-v1", .data = &v1_plat_data },
	{ .compatible = "brcm,genet-v2", .data = &v2_plat_data },
	{ .compatible = "brcm,genet-v3", .data = &v3_plat_data },
	{ .compatible = "brcm,genet-v4", .data = &v4_plat_data },
	{ .compatible = "brcm,genet-v5", .data = &v5_plat_data },
	{ .compatible = "brcm,bcm2711-genet-v5", .data = &bcm2711_plat_data },
	{ },
};
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 device_node *dn = pdev->dev.of_node;
	const struct of_device_id *of_id = NULL;
	const struct bcmgenet_plat_data *pdata;
	struct bcmgenet_priv *priv;
	struct net_device *dev;
	const void *macaddr;
@@ -3458,13 +3497,16 @@ static int bcmgenet_probe(struct platform_device *pdev)

	priv = netdev_priv(dev);
	priv->irq0 = platform_get_irq(pdev, 0);
	if (priv->irq0 < 0) {
		err = priv->irq0;
		goto err;
	}
	priv->irq1 = platform_get_irq(pdev, 1);
	priv->wol_irq = platform_get_irq(pdev, 2);
	if (!priv->irq0 || !priv->irq1) {
		dev_err(&pdev->dev, "can't find IRQs\n");
		err = -EINVAL;
	if (priv->irq1 < 0) {
		err = priv->irq1;
		goto err;
	}
	priv->wol_irq = platform_get_irq_optional(pdev, 2);

	if (dn)
		macaddr = of_get_mac_address(dn);
@@ -3513,10 +3555,14 @@ static int bcmgenet_probe(struct platform_device *pdev)

	priv->dev = dev;
	priv->pdev = pdev;
	if (of_id)
		priv->version = (enum bcmgenet_version)of_id->data;
	else
	if (of_id) {
		pdata = of_id->data;
		priv->version = pdata->version;
		priv->dma_max_burst_length = pdata->dma_max_burst_length;
	} else {
		priv->version = pd->genet_version;
		priv->dma_max_burst_length = DMA_MAX_BURST_LENGTH;
	}

	priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
	if (IS_ERR(priv->clk)) {
+1 −0
Original line number Diff line number Diff line
@@ -664,6 +664,7 @@ struct bcmgenet_priv {
	bool crc_fwd_en;

	unsigned int dma_rx_chk_bit;
	u32 dma_max_burst_length;

	u32 msg_enable;

+25 −22
Original line number Diff line number Diff line
@@ -213,11 +213,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
		udelay(2);
	}

	priv->ext_phy = !priv->internal_phy &&
			(priv->phy_interface != PHY_INTERFACE_MODE_MOCA);

	switch (priv->phy_interface) {
	case PHY_INTERFACE_MODE_INTERNAL:
		phy_name = "internal PHY";
		/* fall through */
	case PHY_INTERFACE_MODE_MOCA:
		/* Irrespective of the actually configured PHY speed (100 or
		 * 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
			port_ctrl = PORT_MODE_INT_EPHY;

		bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);

		if (priv->internal_phy) {
			phy_name = "internal PHY";
		} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
		if (!phy_name) {
			phy_name = "MoCA";
			bcmgenet_moca_phy_setup(priv);
		}
@@ -242,11 +237,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
	case PHY_INTERFACE_MODE_MII:
		phy_name = "external MII";
		phy_set_max_speed(phydev, SPEED_100);
		bcmgenet_sys_writel(priv,
				    PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
		/* Restore the MII PHY after isolation */
		if (bmcr >= 0)
			phy_write(phydev, MII_BMCR, bmcr);
		port_ctrl = PORT_MODE_EXT_EPHY;
		break;

	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;
		else
			port_ctrl = PORT_MODE_EXT_RVMII_25;
		bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
		break;

	case PHY_INTERFACE_MODE_RGMII:
		/* RGMII_NO_ID: TXC transitions at the same time as TXD
		 *		(requires PCB or receiver-side delay)
		 * RGMII:	Add 2ns delay on TXC (90 degree shift)
		 *
		 * ID is implicitly disabled for 100Mbps (RG)MII operation.
		 */
		phy_name = "external RGMII (no delay)";
		id_mode_dis = BIT(16);
		/* fall through */
		port_ctrl = PORT_MODE_EXT_GPHY;
		break;

	case PHY_INTERFACE_MODE_RGMII_TXID:
		if (id_mode_dis)
			phy_name = "external RGMII (no delay)";
		else
		/* RGMII_TXID:	Add 2ns delay on TXC (90 degree shift) */
		phy_name = "external RGMII (TX delay)";
		bcmgenet_sys_writel(priv,
				    PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
		port_ctrl = PORT_MODE_EXT_GPHY;
		break;

	case PHY_INTERFACE_MODE_RGMII_RXID:
		phy_name = "external RGMII (RX delay)";
		port_ctrl = PORT_MODE_EXT_GPHY;
		break;
	default:
		dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
		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
	 * block for the interface to work
	 */