162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/export.h>
1362306a36Sopenharmony_ci#include <bcm63xx_dev_enet.h>
1462306a36Sopenharmony_ci#include <bcm63xx_io.h>
1562306a36Sopenharmony_ci#include <bcm63xx_regs.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic const unsigned long bcm6348_regs_enetdmac[] = {
1862306a36Sopenharmony_ci	[ENETDMAC_CHANCFG]	= ENETDMAC_CHANCFG_REG,
1962306a36Sopenharmony_ci	[ENETDMAC_IR]		= ENETDMAC_IR_REG,
2062306a36Sopenharmony_ci	[ENETDMAC_IRMASK]	= ENETDMAC_IRMASK_REG,
2162306a36Sopenharmony_ci	[ENETDMAC_MAXBURST]	= ENETDMAC_MAXBURST_REG,
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic const unsigned long bcm6345_regs_enetdmac[] = {
2562306a36Sopenharmony_ci	[ENETDMAC_CHANCFG]	= ENETDMA_6345_CHANCFG_REG,
2662306a36Sopenharmony_ci	[ENETDMAC_IR]		= ENETDMA_6345_IR_REG,
2762306a36Sopenharmony_ci	[ENETDMAC_IRMASK]	= ENETDMA_6345_IRMASK_REG,
2862306a36Sopenharmony_ci	[ENETDMAC_MAXBURST]	= ENETDMA_6345_MAXBURST_REG,
2962306a36Sopenharmony_ci	[ENETDMAC_BUFALLOC]	= ENETDMA_6345_BUFALLOC_REG,
3062306a36Sopenharmony_ci	[ENETDMAC_RSTART]	= ENETDMA_6345_RSTART_REG,
3162306a36Sopenharmony_ci	[ENETDMAC_FC]		= ENETDMA_6345_FC_REG,
3262306a36Sopenharmony_ci	[ENETDMAC_LEN]		= ENETDMA_6345_LEN_REG,
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciconst unsigned long *bcm63xx_regs_enetdmac;
3662306a36Sopenharmony_ciEXPORT_SYMBOL(bcm63xx_regs_enetdmac);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic __init void bcm63xx_enetdmac_regs_init(void)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	if (BCMCPU_IS_6345())
4162306a36Sopenharmony_ci		bcm63xx_regs_enetdmac = bcm6345_regs_enetdmac;
4262306a36Sopenharmony_ci	else
4362306a36Sopenharmony_ci		bcm63xx_regs_enetdmac = bcm6348_regs_enetdmac;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic struct resource shared_res[] = {
4762306a36Sopenharmony_ci	{
4862306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
4962306a36Sopenharmony_ci		.end		= -1, /* filled at runtime */
5062306a36Sopenharmony_ci		.flags		= IORESOURCE_MEM,
5162306a36Sopenharmony_ci	},
5262306a36Sopenharmony_ci	{
5362306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
5462306a36Sopenharmony_ci		.end		= -1, /* filled at runtime */
5562306a36Sopenharmony_ci		.flags		= IORESOURCE_MEM,
5662306a36Sopenharmony_ci	},
5762306a36Sopenharmony_ci	{
5862306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
5962306a36Sopenharmony_ci		.end		= -1, /* filled at runtime */
6062306a36Sopenharmony_ci		.flags		= IORESOURCE_MEM,
6162306a36Sopenharmony_ci	},
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic struct platform_device bcm63xx_enet_shared_device = {
6562306a36Sopenharmony_ci	.name		= "bcm63xx_enet_shared",
6662306a36Sopenharmony_ci	.id		= 0,
6762306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(shared_res),
6862306a36Sopenharmony_ci	.resource	= shared_res,
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int shared_device_registered;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic u64 enet_dmamask = DMA_BIT_MASK(32);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic struct resource enet0_res[] = {
7662306a36Sopenharmony_ci	{
7762306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
7862306a36Sopenharmony_ci		.end		= -1, /* filled at runtime */
7962306a36Sopenharmony_ci		.flags		= IORESOURCE_MEM,
8062306a36Sopenharmony_ci	},
8162306a36Sopenharmony_ci	{
8262306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
8362306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
8462306a36Sopenharmony_ci	},
8562306a36Sopenharmony_ci	{
8662306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
8762306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
8862306a36Sopenharmony_ci	},
8962306a36Sopenharmony_ci	{
9062306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
9162306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
9262306a36Sopenharmony_ci	},
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic struct bcm63xx_enet_platform_data enet0_pd;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct platform_device bcm63xx_enet0_device = {
9862306a36Sopenharmony_ci	.name		= "bcm63xx_enet",
9962306a36Sopenharmony_ci	.id		= 0,
10062306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(enet0_res),
10162306a36Sopenharmony_ci	.resource	= enet0_res,
10262306a36Sopenharmony_ci	.dev		= {
10362306a36Sopenharmony_ci		.platform_data = &enet0_pd,
10462306a36Sopenharmony_ci		.dma_mask = &enet_dmamask,
10562306a36Sopenharmony_ci		.coherent_dma_mask = DMA_BIT_MASK(32),
10662306a36Sopenharmony_ci	},
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic struct resource enet1_res[] = {
11062306a36Sopenharmony_ci	{
11162306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
11262306a36Sopenharmony_ci		.end		= -1, /* filled at runtime */
11362306a36Sopenharmony_ci		.flags		= IORESOURCE_MEM,
11462306a36Sopenharmony_ci	},
11562306a36Sopenharmony_ci	{
11662306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
11762306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
11862306a36Sopenharmony_ci	},
11962306a36Sopenharmony_ci	{
12062306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
12162306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
12262306a36Sopenharmony_ci	},
12362306a36Sopenharmony_ci	{
12462306a36Sopenharmony_ci		.start		= -1, /* filled at runtime */
12562306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
12662306a36Sopenharmony_ci	},
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic struct bcm63xx_enet_platform_data enet1_pd;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic struct platform_device bcm63xx_enet1_device = {
13262306a36Sopenharmony_ci	.name		= "bcm63xx_enet",
13362306a36Sopenharmony_ci	.id		= 1,
13462306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(enet1_res),
13562306a36Sopenharmony_ci	.resource	= enet1_res,
13662306a36Sopenharmony_ci	.dev		= {
13762306a36Sopenharmony_ci		.platform_data = &enet1_pd,
13862306a36Sopenharmony_ci		.dma_mask = &enet_dmamask,
13962306a36Sopenharmony_ci		.coherent_dma_mask = DMA_BIT_MASK(32),
14062306a36Sopenharmony_ci	},
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic struct resource enetsw_res[] = {
14462306a36Sopenharmony_ci	{
14562306a36Sopenharmony_ci		/* start & end filled at runtime */
14662306a36Sopenharmony_ci		.flags		= IORESOURCE_MEM,
14762306a36Sopenharmony_ci	},
14862306a36Sopenharmony_ci	{
14962306a36Sopenharmony_ci		/* start filled at runtime */
15062306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
15162306a36Sopenharmony_ci	},
15262306a36Sopenharmony_ci	{
15362306a36Sopenharmony_ci		/* start filled at runtime */
15462306a36Sopenharmony_ci		.flags		= IORESOURCE_IRQ,
15562306a36Sopenharmony_ci	},
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic struct bcm63xx_enetsw_platform_data enetsw_pd;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic struct platform_device bcm63xx_enetsw_device = {
16162306a36Sopenharmony_ci	.name		= "bcm63xx_enetsw",
16262306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(enetsw_res),
16362306a36Sopenharmony_ci	.resource	= enetsw_res,
16462306a36Sopenharmony_ci	.dev		= {
16562306a36Sopenharmony_ci		.platform_data = &enetsw_pd,
16662306a36Sopenharmony_ci		.dma_mask = &enet_dmamask,
16762306a36Sopenharmony_ci		.coherent_dma_mask = DMA_BIT_MASK(32),
16862306a36Sopenharmony_ci	},
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int __init register_shared(void)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int ret, chan_count;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (shared_device_registered)
17662306a36Sopenharmony_ci		return 0;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	bcm63xx_enetdmac_regs_init();
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
18162306a36Sopenharmony_ci	shared_res[0].end = shared_res[0].start;
18262306a36Sopenharmony_ci	if (BCMCPU_IS_6345())
18362306a36Sopenharmony_ci		shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1;
18462306a36Sopenharmony_ci	else
18562306a36Sopenharmony_ci		shared_res[0].end += (RSET_ENETDMA_SIZE)  - 1;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
18862306a36Sopenharmony_ci		chan_count = 32;
18962306a36Sopenharmony_ci	else if (BCMCPU_IS_6345())
19062306a36Sopenharmony_ci		chan_count = 8;
19162306a36Sopenharmony_ci	else
19262306a36Sopenharmony_ci		chan_count = 16;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
19562306a36Sopenharmony_ci	shared_res[1].end = shared_res[1].start;
19662306a36Sopenharmony_ci	shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count)  - 1;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
19962306a36Sopenharmony_ci	shared_res[2].end = shared_res[2].start;
20062306a36Sopenharmony_ci	shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count)  - 1;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ret = platform_device_register(&bcm63xx_enet_shared_device);
20362306a36Sopenharmony_ci	if (ret)
20462306a36Sopenharmony_ci		return ret;
20562306a36Sopenharmony_ci	shared_device_registered = 1;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return 0;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciint __init bcm63xx_enet_register(int unit,
21162306a36Sopenharmony_ci				 const struct bcm63xx_enet_platform_data *pd)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct platform_device *pdev;
21462306a36Sopenharmony_ci	struct bcm63xx_enet_platform_data *dpd;
21562306a36Sopenharmony_ci	int ret;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (unit > 1)
21862306a36Sopenharmony_ci		return -ENODEV;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345()))
22162306a36Sopenharmony_ci		return -ENODEV;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	ret = register_shared();
22462306a36Sopenharmony_ci	if (ret)
22562306a36Sopenharmony_ci		return ret;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (unit == 0) {
22862306a36Sopenharmony_ci		enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
22962306a36Sopenharmony_ci		enet0_res[0].end = enet0_res[0].start;
23062306a36Sopenharmony_ci		enet0_res[0].end += RSET_ENET_SIZE - 1;
23162306a36Sopenharmony_ci		enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0);
23262306a36Sopenharmony_ci		enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA);
23362306a36Sopenharmony_ci		enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA);
23462306a36Sopenharmony_ci		pdev = &bcm63xx_enet0_device;
23562306a36Sopenharmony_ci	} else {
23662306a36Sopenharmony_ci		enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1);
23762306a36Sopenharmony_ci		enet1_res[0].end = enet1_res[0].start;
23862306a36Sopenharmony_ci		enet1_res[0].end += RSET_ENET_SIZE - 1;
23962306a36Sopenharmony_ci		enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1);
24062306a36Sopenharmony_ci		enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA);
24162306a36Sopenharmony_ci		enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA);
24262306a36Sopenharmony_ci		pdev = &bcm63xx_enet1_device;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* copy given platform data */
24662306a36Sopenharmony_ci	dpd = pdev->dev.platform_data;
24762306a36Sopenharmony_ci	memcpy(dpd, pd, sizeof(*pd));
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* adjust them in case internal phy is used */
25062306a36Sopenharmony_ci	if (dpd->use_internal_phy) {
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		/* internal phy only exists for enet0 */
25362306a36Sopenharmony_ci		if (unit == 1)
25462306a36Sopenharmony_ci			return -ENODEV;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		dpd->phy_id = 1;
25762306a36Sopenharmony_ci		dpd->has_phy_interrupt = 1;
25862306a36Sopenharmony_ci		dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
26262306a36Sopenharmony_ci	dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
26362306a36Sopenharmony_ci	if (BCMCPU_IS_6345()) {
26462306a36Sopenharmony_ci		dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK;
26562306a36Sopenharmony_ci		dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK;
26662306a36Sopenharmony_ci		dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK;
26762306a36Sopenharmony_ci		dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK;
26862306a36Sopenharmony_ci		dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK;
26962306a36Sopenharmony_ci		dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH;
27062306a36Sopenharmony_ci		dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT;
27162306a36Sopenharmony_ci	} else {
27262306a36Sopenharmony_ci		dpd->dma_has_sram = true;
27362306a36Sopenharmony_ci		dpd->dma_chan_width = ENETDMA_CHAN_WIDTH;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (unit == 0) {
27762306a36Sopenharmony_ci		dpd->rx_chan = 0;
27862306a36Sopenharmony_ci		dpd->tx_chan = 1;
27962306a36Sopenharmony_ci	} else {
28062306a36Sopenharmony_ci		dpd->rx_chan = 2;
28162306a36Sopenharmony_ci		dpd->tx_chan = 3;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	ret = platform_device_register(pdev);
28562306a36Sopenharmony_ci	if (ret)
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ciint __init
29162306a36Sopenharmony_cibcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int ret;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
29662306a36Sopenharmony_ci		return -ENODEV;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	ret = register_shared();
29962306a36Sopenharmony_ci	if (ret)
30062306a36Sopenharmony_ci		return ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW);
30362306a36Sopenharmony_ci	enetsw_res[0].end = enetsw_res[0].start;
30462306a36Sopenharmony_ci	enetsw_res[0].end += RSET_ENETSW_SIZE - 1;
30562306a36Sopenharmony_ci	enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0);
30662306a36Sopenharmony_ci	enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0);
30762306a36Sopenharmony_ci	if (!enetsw_res[2].start)
30862306a36Sopenharmony_ci		enetsw_res[2].start = -1;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (BCMCPU_IS_6328())
31362306a36Sopenharmony_ci		enetsw_pd.num_ports = ENETSW_PORTS_6328;
31462306a36Sopenharmony_ci	else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
31562306a36Sopenharmony_ci		enetsw_pd.num_ports = ENETSW_PORTS_6368;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	enetsw_pd.dma_has_sram = true;
31862306a36Sopenharmony_ci	enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH;
31962306a36Sopenharmony_ci	enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
32062306a36Sopenharmony_ci	enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	ret = platform_device_register(&bcm63xx_enetsw_device);
32362306a36Sopenharmony_ci	if (ret)
32462306a36Sopenharmony_ci		return ret;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci}
328