Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f00a022 authored by Maxime Bizon's avatar Maxime Bizon Committed by David S. Miller
Browse files

bcm63xx_enet: add support for Broadcom BCM63xx integrated gigabit switch



Newer Broadcom BCM63xx SoCs: 6328, 6362 and 6368 have an integrated switch
which needs to be driven slightly differently from the traditional
external switches. This patch introduces changes in arch/mips/bcm63xx in order
to:

- register a bcm63xx_enetsw driver instead of bcm63xx_enet driver
- update DMA channels configuration & state RAM base addresses
- add a new platform data configuration knob to define the number of
  ports per switch/device and force link on some ports
- define the required switch registers

On the driver side, the following changes are required:

- the switch ports need to be polled to ensure the link is up and
  running and RX/TX can properly work
- basic switch configuration needs to be performed for the switch to
  forward packets to the CPU
- update the MIB counters since the integrated

Signed-off-by: default avatarMaxime Bizon <mbizon@freebox.fr>
Signed-off-by: default avatarJonas Gorski <jogo@openwrt.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ae99b5f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -845,6 +845,10 @@ int __init board_register_devices(void)
	    !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
		bcm63xx_enet_register(1, &board.enet1);

	if (board.has_enetsw &&
	    !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
		bcm63xx_enetsw_register(&board.enetsw);

	if (board.has_usbd)
		bcm63xx_usbd_register(&board.usbd);

+95 −18
Original line number Diff line number Diff line
@@ -104,38 +104,81 @@ static struct platform_device bcm63xx_enet1_device = {
	},
};

int __init bcm63xx_enet_register(int unit,
				 const struct bcm63xx_enet_platform_data *pd)
static struct resource enetsw_res[] = {
	{
	struct platform_device *pdev;
	struct bcm63xx_enet_platform_data *dpd;
	int ret;
		/* start & end filled at runtime */
		.flags		= IORESOURCE_MEM,
	},
	{
		/* start filled at runtime */
		.flags		= IORESOURCE_IRQ,
	},
	{
		/* start filled at runtime */
		.flags		= IORESOURCE_IRQ,
	},
};

	if (unit > 1)
		return -ENODEV;
static struct bcm63xx_enetsw_platform_data enetsw_pd;

	if (unit == 1 && BCMCPU_IS_6338())
		return -ENODEV;
static struct platform_device bcm63xx_enetsw_device = {
	.name		= "bcm63xx_enetsw",
	.num_resources	= ARRAY_SIZE(enetsw_res),
	.resource	= enetsw_res,
	.dev		= {
		.platform_data = &enetsw_pd,
	},
};

static int __init register_shared(void)
{
	int ret, chan_count;

	if (shared_device_registered)
		return 0;

	if (!shared_device_registered) {
	shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
	shared_res[0].end = shared_res[0].start;
	shared_res[0].end += (RSET_ENETDMA_SIZE)  - 1;

	if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
		chan_count = 32;
	else
		chan_count = 16;

	shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
	shared_res[1].end = shared_res[1].start;
		shared_res[1].end += RSET_ENETDMAC_SIZE(16)  - 1;
	shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count)  - 1;

	shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
	shared_res[2].end = shared_res[2].start;
		shared_res[2].end += RSET_ENETDMAS_SIZE(16)  - 1;
	shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count)  - 1;

	ret = platform_device_register(&bcm63xx_enet_shared_device);
	if (ret)
		return ret;
	shared_device_registered = 1;

	return 0;
}

int __init bcm63xx_enet_register(int unit,
				 const struct bcm63xx_enet_platform_data *pd)
{
	struct platform_device *pdev;
	struct bcm63xx_enet_platform_data *dpd;
	int ret;

	if (unit > 1)
		return -ENODEV;

	if (unit == 1 && BCMCPU_IS_6338())
		return -ENODEV;

	ret = register_shared();
	if (ret)
		return ret;

	if (unit == 0) {
		enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
		enet0_res[0].end = enet0_res[0].start;
@@ -175,3 +218,37 @@ int __init bcm63xx_enet_register(int unit,
		return ret;
	return 0;
}

int __init
bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
{
	int ret;

	if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
		return -ENODEV;

	ret = register_shared();
	if (ret)
		return ret;

	enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW);
	enetsw_res[0].end = enetsw_res[0].start;
	enetsw_res[0].end += RSET_ENETSW_SIZE - 1;
	enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0);
	enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0);
	if (!enetsw_res[2].start)
		enetsw_res[2].start = -1;

	memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));

	if (BCMCPU_IS_6328())
		enetsw_pd.num_ports = ENETSW_PORTS_6328;
	else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
		enetsw_pd.num_ports = ENETSW_PORTS_6368;

	ret = platform_device_register(&bcm63xx_enetsw_device);
	if (ret)
		return ret;

	return 0;
}
+28 −0
Original line number Diff line number Diff line
@@ -39,7 +39,35 @@ struct bcm63xx_enet_platform_data {
					    int phy_id, int reg, int val));
};

/*
 * on board ethernet switch platform data
 */
#define ENETSW_MAX_PORT	8
#define ENETSW_PORTS_6328 5 /* 4 FE PHY + 1 RGMII */
#define ENETSW_PORTS_6368 6 /* 4 FE PHY + 2 RGMII */

#define ENETSW_RGMII_PORT0	4

struct bcm63xx_enetsw_port {
	int		used;
	int		phy_id;

	int		bypass_link;
	int		force_speed;
	int		force_duplex_full;

	const char	*name;
};

struct bcm63xx_enetsw_platform_data {
	char mac_addr[ETH_ALEN];
	int num_ports;
	struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT];
};

int __init bcm63xx_enet_register(int unit,
				 const struct bcm63xx_enet_platform_data *pd);

int bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd);

#endif /* ! BCM63XX_DEV_ENET_H_ */
+50 −0
Original line number Diff line number Diff line
@@ -830,10 +830,60 @@
 * _REG relative to RSET_ENETSW
 *************************************************************************/

/* Port traffic control */
#define ENETSW_PTCTRL_REG(x)		(0x0 + (x))
#define ENETSW_PTCTRL_RXDIS_MASK	(1 << 0)
#define ENETSW_PTCTRL_TXDIS_MASK	(1 << 1)

/* Switch mode register */
#define ENETSW_SWMODE_REG		(0xb)
#define ENETSW_SWMODE_FWD_EN_MASK	(1 << 1)

/* IMP override Register */
#define ENETSW_IMPOV_REG		(0xe)
#define ENETSW_IMPOV_FORCE_MASK		(1 << 7)
#define ENETSW_IMPOV_TXFLOW_MASK	(1 << 5)
#define ENETSW_IMPOV_RXFLOW_MASK	(1 << 4)
#define ENETSW_IMPOV_1000_MASK		(1 << 3)
#define ENETSW_IMPOV_100_MASK		(1 << 2)
#define ENETSW_IMPOV_FDX_MASK		(1 << 1)
#define ENETSW_IMPOV_LINKUP_MASK	(1 << 0)

/* Port override Register */
#define ENETSW_PORTOV_REG(x)		(0x58 + (x))
#define ENETSW_PORTOV_ENABLE_MASK	(1 << 6)
#define ENETSW_PORTOV_TXFLOW_MASK	(1 << 5)
#define ENETSW_PORTOV_RXFLOW_MASK	(1 << 4)
#define ENETSW_PORTOV_1000_MASK		(1 << 3)
#define ENETSW_PORTOV_100_MASK		(1 << 2)
#define ENETSW_PORTOV_FDX_MASK		(1 << 1)
#define ENETSW_PORTOV_LINKUP_MASK	(1 << 0)

/* MDIO control register */
#define ENETSW_MDIOC_REG		(0xb0)
#define ENETSW_MDIOC_EXT_MASK		(1 << 16)
#define ENETSW_MDIOC_REG_SHIFT		20
#define ENETSW_MDIOC_PHYID_SHIFT	25
#define ENETSW_MDIOC_RD_MASK		(1 << 30)
#define ENETSW_MDIOC_WR_MASK		(1 << 31)

/* MDIO data register */
#define ENETSW_MDIOD_REG		(0xb4)

/* Global Management Configuration Register */
#define ENETSW_GMCR_REG			(0x200)
#define ENETSW_GMCR_RST_MIB_MASK	(1 << 0)

/* MIB register */
#define ENETSW_MIB_REG(x)		(0x2800 + (x) * 4)
#define ENETSW_MIB_REG_COUNT		47

/* Jumbo control register port mask register */
#define ENETSW_JMBCTL_PORT_REG		(0x4004)

/* Jumbo control mib good frame register */
#define ENETSW_JMBCTL_MAXSIZE_REG	(0x4008)


/*************************************************************************
 * _REG relative to RSET_OHCI_PRIV
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ struct board_info {
	/* enabled feature/device */
	unsigned int	has_enet0:1;
	unsigned int	has_enet1:1;
	unsigned int	has_enetsw:1;
	unsigned int	has_pci:1;
	unsigned int	has_pccard:1;
	unsigned int	has_ohci0:1;
@@ -36,6 +37,7 @@ struct board_info {
	/* ethernet config */
	struct bcm63xx_enet_platform_data enet0;
	struct bcm63xx_enet_platform_data enet1;
	struct bcm63xx_enetsw_platform_data enetsw;

	/* USB config */
	struct bcm63xx_usbd_platform_data usbd;
Loading