aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorMaxime Bizon <mbizon@freebox.fr>2013-06-04 17:53:35 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-10 17:28:28 -0400
commit6f00a0229627ca189529cad3f9154ac2f9e5c7db (patch)
tree20b010b5faa5fca26951f3f3575da92a9cf317fc /arch/mips
parent0ae99b5fede6f3a8d252d50bb4aba29544295219 (diff)
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: Maxime Bizon <mbizon@freebox.fr> Signed-off-by: Jonas Gorski <jogo@openwrt.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c4
-rw-r--r--arch/mips/bcm63xx/dev-enet.c113
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h28
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h50
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h2
5 files changed, 179 insertions, 18 deletions
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
index a9505c4867e8..9c0ddafafb6c 100644
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -845,6 +845,10 @@ int __init board_register_devices(void)
845 !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr)) 845 !bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
846 bcm63xx_enet_register(1, &board.enet1); 846 bcm63xx_enet_register(1, &board.enet1);
847 847
848 if (board.has_enetsw &&
849 !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
850 bcm63xx_enetsw_register(&board.enetsw);
851
848 if (board.has_usbd) 852 if (board.has_usbd)
849 bcm63xx_usbd_register(&board.usbd); 853 bcm63xx_usbd_register(&board.usbd);
850 854
diff --git a/arch/mips/bcm63xx/dev-enet.c b/arch/mips/bcm63xx/dev-enet.c
index df5bf6686942..6cbaee0f6d70 100644
--- a/arch/mips/bcm63xx/dev-enet.c
+++ b/arch/mips/bcm63xx/dev-enet.c
@@ -104,6 +104,64 @@ static struct platform_device bcm63xx_enet1_device = {
104 }, 104 },
105}; 105};
106 106
107static struct resource enetsw_res[] = {
108 {
109 /* start & end filled at runtime */
110 .flags = IORESOURCE_MEM,
111 },
112 {
113 /* start filled at runtime */
114 .flags = IORESOURCE_IRQ,
115 },
116 {
117 /* start filled at runtime */
118 .flags = IORESOURCE_IRQ,
119 },
120};
121
122static struct bcm63xx_enetsw_platform_data enetsw_pd;
123
124static struct platform_device bcm63xx_enetsw_device = {
125 .name = "bcm63xx_enetsw",
126 .num_resources = ARRAY_SIZE(enetsw_res),
127 .resource = enetsw_res,
128 .dev = {
129 .platform_data = &enetsw_pd,
130 },
131};
132
133static int __init register_shared(void)
134{
135 int ret, chan_count;
136
137 if (shared_device_registered)
138 return 0;
139
140 shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
141 shared_res[0].end = shared_res[0].start;
142 shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
143
144 if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
145 chan_count = 32;
146 else
147 chan_count = 16;
148
149 shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
150 shared_res[1].end = shared_res[1].start;
151 shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count) - 1;
152
153 shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
154 shared_res[2].end = shared_res[2].start;
155 shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count) - 1;
156
157 ret = platform_device_register(&bcm63xx_enet_shared_device);
158 if (ret)
159 return ret;
160 shared_device_registered = 1;
161
162 return 0;
163}
164
107int __init bcm63xx_enet_register(int unit, 165int __init bcm63xx_enet_register(int unit,
108 const struct bcm63xx_enet_platform_data *pd) 166 const struct bcm63xx_enet_platform_data *pd)
109{ 167{
@@ -117,24 +175,9 @@ int __init bcm63xx_enet_register(int unit,
117 if (unit == 1 && BCMCPU_IS_6338()) 175 if (unit == 1 && BCMCPU_IS_6338())
118 return -ENODEV; 176 return -ENODEV;
119 177
120 if (!shared_device_registered) { 178 ret = register_shared();
121 shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); 179 if (ret)
122 shared_res[0].end = shared_res[0].start; 180 return ret;
123 shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
124
125 shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
126 shared_res[1].end = shared_res[1].start;
127 shared_res[1].end += RSET_ENETDMAC_SIZE(16) - 1;
128
129 shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
130 shared_res[2].end = shared_res[2].start;
131 shared_res[2].end += RSET_ENETDMAS_SIZE(16) - 1;
132
133 ret = platform_device_register(&bcm63xx_enet_shared_device);
134 if (ret)
135 return ret;
136 shared_device_registered = 1;
137 }
138 181
139 if (unit == 0) { 182 if (unit == 0) {
140 enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0); 183 enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
@@ -175,3 +218,37 @@ int __init bcm63xx_enet_register(int unit,
175 return ret; 218 return ret;
176 return 0; 219 return 0;
177} 220}
221
222int __init
223bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
224{
225 int ret;
226
227 if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
228 return -ENODEV;
229
230 ret = register_shared();
231 if (ret)
232 return ret;
233
234 enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW);
235 enetsw_res[0].end = enetsw_res[0].start;
236 enetsw_res[0].end += RSET_ENETSW_SIZE - 1;
237 enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0);
238 enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0);
239 if (!enetsw_res[2].start)
240 enetsw_res[2].start = -1;
241
242 memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
243
244 if (BCMCPU_IS_6328())
245 enetsw_pd.num_ports = ENETSW_PORTS_6328;
246 else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
247 enetsw_pd.num_ports = ENETSW_PORTS_6368;
248
249 ret = platform_device_register(&bcm63xx_enetsw_device);
250 if (ret)
251 return ret;
252
253 return 0;
254}
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
index d53f611184b9..118e3c938841 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
@@ -39,7 +39,35 @@ struct bcm63xx_enet_platform_data {
39 int phy_id, int reg, int val)); 39 int phy_id, int reg, int val));
40}; 40};
41 41
42/*
43 * on board ethernet switch platform data
44 */
45#define ENETSW_MAX_PORT 8
46#define ENETSW_PORTS_6328 5 /* 4 FE PHY + 1 RGMII */
47#define ENETSW_PORTS_6368 6 /* 4 FE PHY + 2 RGMII */
48
49#define ENETSW_RGMII_PORT0 4
50
51struct bcm63xx_enetsw_port {
52 int used;
53 int phy_id;
54
55 int bypass_link;
56 int force_speed;
57 int force_duplex_full;
58
59 const char *name;
60};
61
62struct bcm63xx_enetsw_platform_data {
63 char mac_addr[ETH_ALEN];
64 int num_ports;
65 struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT];
66};
67
42int __init bcm63xx_enet_register(int unit, 68int __init bcm63xx_enet_register(int unit,
43 const struct bcm63xx_enet_platform_data *pd); 69 const struct bcm63xx_enet_platform_data *pd);
44 70
71int bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd);
72
45#endif /* ! BCM63XX_DEV_ENET_H_ */ 73#endif /* ! BCM63XX_DEV_ENET_H_ */
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
index 3203fe49b34d..0a2121abb1a6 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -830,10 +830,60 @@
830 * _REG relative to RSET_ENETSW 830 * _REG relative to RSET_ENETSW
831 *************************************************************************/ 831 *************************************************************************/
832 832
833/* Port traffic control */
834#define ENETSW_PTCTRL_REG(x) (0x0 + (x))
835#define ENETSW_PTCTRL_RXDIS_MASK (1 << 0)
836#define ENETSW_PTCTRL_TXDIS_MASK (1 << 1)
837
838/* Switch mode register */
839#define ENETSW_SWMODE_REG (0xb)
840#define ENETSW_SWMODE_FWD_EN_MASK (1 << 1)
841
842/* IMP override Register */
843#define ENETSW_IMPOV_REG (0xe)
844#define ENETSW_IMPOV_FORCE_MASK (1 << 7)
845#define ENETSW_IMPOV_TXFLOW_MASK (1 << 5)
846#define ENETSW_IMPOV_RXFLOW_MASK (1 << 4)
847#define ENETSW_IMPOV_1000_MASK (1 << 3)
848#define ENETSW_IMPOV_100_MASK (1 << 2)
849#define ENETSW_IMPOV_FDX_MASK (1 << 1)
850#define ENETSW_IMPOV_LINKUP_MASK (1 << 0)
851
852/* Port override Register */
853#define ENETSW_PORTOV_REG(x) (0x58 + (x))
854#define ENETSW_PORTOV_ENABLE_MASK (1 << 6)
855#define ENETSW_PORTOV_TXFLOW_MASK (1 << 5)
856#define ENETSW_PORTOV_RXFLOW_MASK (1 << 4)
857#define ENETSW_PORTOV_1000_MASK (1 << 3)
858#define ENETSW_PORTOV_100_MASK (1 << 2)
859#define ENETSW_PORTOV_FDX_MASK (1 << 1)
860#define ENETSW_PORTOV_LINKUP_MASK (1 << 0)
861
862/* MDIO control register */
863#define ENETSW_MDIOC_REG (0xb0)
864#define ENETSW_MDIOC_EXT_MASK (1 << 16)
865#define ENETSW_MDIOC_REG_SHIFT 20
866#define ENETSW_MDIOC_PHYID_SHIFT 25
867#define ENETSW_MDIOC_RD_MASK (1 << 30)
868#define ENETSW_MDIOC_WR_MASK (1 << 31)
869
870/* MDIO data register */
871#define ENETSW_MDIOD_REG (0xb4)
872
873/* Global Management Configuration Register */
874#define ENETSW_GMCR_REG (0x200)
875#define ENETSW_GMCR_RST_MIB_MASK (1 << 0)
876
833/* MIB register */ 877/* MIB register */
834#define ENETSW_MIB_REG(x) (0x2800 + (x) * 4) 878#define ENETSW_MIB_REG(x) (0x2800 + (x) * 4)
835#define ENETSW_MIB_REG_COUNT 47 879#define ENETSW_MIB_REG_COUNT 47
836 880
881/* Jumbo control register port mask register */
882#define ENETSW_JMBCTL_PORT_REG (0x4004)
883
884/* Jumbo control mib good frame register */
885#define ENETSW_JMBCTL_MAXSIZE_REG (0x4008)
886
837 887
838/************************************************************************* 888/*************************************************************************
839 * _REG relative to RSET_OHCI_PRIV 889 * _REG relative to RSET_OHCI_PRIV
diff --git a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
index 682bcf3b492a..d9aee1a833f3 100644
--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
@@ -24,6 +24,7 @@ struct board_info {
24 /* enabled feature/device */ 24 /* enabled feature/device */
25 unsigned int has_enet0:1; 25 unsigned int has_enet0:1;
26 unsigned int has_enet1:1; 26 unsigned int has_enet1:1;
27 unsigned int has_enetsw:1;
27 unsigned int has_pci:1; 28 unsigned int has_pci:1;
28 unsigned int has_pccard:1; 29 unsigned int has_pccard:1;
29 unsigned int has_ohci0:1; 30 unsigned int has_ohci0:1;
@@ -36,6 +37,7 @@ struct board_info {
36 /* ethernet config */ 37 /* ethernet config */
37 struct bcm63xx_enet_platform_data enet0; 38 struct bcm63xx_enet_platform_data enet0;
38 struct bcm63xx_enet_platform_data enet1; 39 struct bcm63xx_enet_platform_data enet1;
40 struct bcm63xx_enetsw_platform_data enetsw;
39 41
40 /* USB config */ 42 /* USB config */
41 struct bcm63xx_usbd_platform_data usbd; 43 struct bcm63xx_usbd_platform_data usbd;