diff options
Diffstat (limited to 'arch/mips/bcm63xx/dev-enet.c')
-rw-r--r-- | arch/mips/bcm63xx/dev-enet.c | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/arch/mips/bcm63xx/dev-enet.c b/arch/mips/bcm63xx/dev-enet.c new file mode 100644 index 000000000..8e73d65f3 --- /dev/null +++ b/arch/mips/bcm63xx/dev-enet.c | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/export.h> | ||
13 | #include <bcm63xx_dev_enet.h> | ||
14 | #include <bcm63xx_io.h> | ||
15 | #include <bcm63xx_regs.h> | ||
16 | |||
17 | static const unsigned long bcm6348_regs_enetdmac[] = { | ||
18 | [ENETDMAC_CHANCFG] = ENETDMAC_CHANCFG_REG, | ||
19 | [ENETDMAC_IR] = ENETDMAC_IR_REG, | ||
20 | [ENETDMAC_IRMASK] = ENETDMAC_IRMASK_REG, | ||
21 | [ENETDMAC_MAXBURST] = ENETDMAC_MAXBURST_REG, | ||
22 | }; | ||
23 | |||
24 | static const unsigned long bcm6345_regs_enetdmac[] = { | ||
25 | [ENETDMAC_CHANCFG] = ENETDMA_6345_CHANCFG_REG, | ||
26 | [ENETDMAC_IR] = ENETDMA_6345_IR_REG, | ||
27 | [ENETDMAC_IRMASK] = ENETDMA_6345_IRMASK_REG, | ||
28 | [ENETDMAC_MAXBURST] = ENETDMA_6345_MAXBURST_REG, | ||
29 | [ENETDMAC_BUFALLOC] = ENETDMA_6345_BUFALLOC_REG, | ||
30 | [ENETDMAC_RSTART] = ENETDMA_6345_RSTART_REG, | ||
31 | [ENETDMAC_FC] = ENETDMA_6345_FC_REG, | ||
32 | [ENETDMAC_LEN] = ENETDMA_6345_LEN_REG, | ||
33 | }; | ||
34 | |||
35 | const unsigned long *bcm63xx_regs_enetdmac; | ||
36 | EXPORT_SYMBOL(bcm63xx_regs_enetdmac); | ||
37 | |||
38 | static __init void bcm63xx_enetdmac_regs_init(void) | ||
39 | { | ||
40 | if (BCMCPU_IS_6345()) | ||
41 | bcm63xx_regs_enetdmac = bcm6345_regs_enetdmac; | ||
42 | else | ||
43 | bcm63xx_regs_enetdmac = bcm6348_regs_enetdmac; | ||
44 | } | ||
45 | |||
46 | static struct resource shared_res[] = { | ||
47 | { | ||
48 | .start = -1, /* filled at runtime */ | ||
49 | .end = -1, /* filled at runtime */ | ||
50 | .flags = IORESOURCE_MEM, | ||
51 | }, | ||
52 | { | ||
53 | .start = -1, /* filled at runtime */ | ||
54 | .end = -1, /* filled at runtime */ | ||
55 | .flags = IORESOURCE_MEM, | ||
56 | }, | ||
57 | { | ||
58 | .start = -1, /* filled at runtime */ | ||
59 | .end = -1, /* filled at runtime */ | ||
60 | .flags = IORESOURCE_MEM, | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | static struct platform_device bcm63xx_enet_shared_device = { | ||
65 | .name = "bcm63xx_enet_shared", | ||
66 | .id = 0, | ||
67 | .num_resources = ARRAY_SIZE(shared_res), | ||
68 | .resource = shared_res, | ||
69 | }; | ||
70 | |||
71 | static int shared_device_registered; | ||
72 | |||
73 | static u64 enet_dmamask = DMA_BIT_MASK(32); | ||
74 | |||
75 | static struct resource enet0_res[] = { | ||
76 | { | ||
77 | .start = -1, /* filled at runtime */ | ||
78 | .end = -1, /* filled at runtime */ | ||
79 | .flags = IORESOURCE_MEM, | ||
80 | }, | ||
81 | { | ||
82 | .start = -1, /* filled at runtime */ | ||
83 | .flags = IORESOURCE_IRQ, | ||
84 | }, | ||
85 | { | ||
86 | .start = -1, /* filled at runtime */ | ||
87 | .flags = IORESOURCE_IRQ, | ||
88 | }, | ||
89 | { | ||
90 | .start = -1, /* filled at runtime */ | ||
91 | .flags = IORESOURCE_IRQ, | ||
92 | }, | ||
93 | }; | ||
94 | |||
95 | static struct bcm63xx_enet_platform_data enet0_pd; | ||
96 | |||
97 | static struct platform_device bcm63xx_enet0_device = { | ||
98 | .name = "bcm63xx_enet", | ||
99 | .id = 0, | ||
100 | .num_resources = ARRAY_SIZE(enet0_res), | ||
101 | .resource = enet0_res, | ||
102 | .dev = { | ||
103 | .platform_data = &enet0_pd, | ||
104 | .dma_mask = &enet_dmamask, | ||
105 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
106 | }, | ||
107 | }; | ||
108 | |||
109 | static struct resource enet1_res[] = { | ||
110 | { | ||
111 | .start = -1, /* filled at runtime */ | ||
112 | .end = -1, /* filled at runtime */ | ||
113 | .flags = IORESOURCE_MEM, | ||
114 | }, | ||
115 | { | ||
116 | .start = -1, /* filled at runtime */ | ||
117 | .flags = IORESOURCE_IRQ, | ||
118 | }, | ||
119 | { | ||
120 | .start = -1, /* filled at runtime */ | ||
121 | .flags = IORESOURCE_IRQ, | ||
122 | }, | ||
123 | { | ||
124 | .start = -1, /* filled at runtime */ | ||
125 | .flags = IORESOURCE_IRQ, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | static struct bcm63xx_enet_platform_data enet1_pd; | ||
130 | |||
131 | static struct platform_device bcm63xx_enet1_device = { | ||
132 | .name = "bcm63xx_enet", | ||
133 | .id = 1, | ||
134 | .num_resources = ARRAY_SIZE(enet1_res), | ||
135 | .resource = enet1_res, | ||
136 | .dev = { | ||
137 | .platform_data = &enet1_pd, | ||
138 | .dma_mask = &enet_dmamask, | ||
139 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
140 | }, | ||
141 | }; | ||
142 | |||
143 | static struct resource enetsw_res[] = { | ||
144 | { | ||
145 | /* start & end filled at runtime */ | ||
146 | .flags = IORESOURCE_MEM, | ||
147 | }, | ||
148 | { | ||
149 | /* start filled at runtime */ | ||
150 | .flags = IORESOURCE_IRQ, | ||
151 | }, | ||
152 | { | ||
153 | /* start filled at runtime */ | ||
154 | .flags = IORESOURCE_IRQ, | ||
155 | }, | ||
156 | }; | ||
157 | |||
158 | static struct bcm63xx_enetsw_platform_data enetsw_pd; | ||
159 | |||
160 | static struct platform_device bcm63xx_enetsw_device = { | ||
161 | .name = "bcm63xx_enetsw", | ||
162 | .num_resources = ARRAY_SIZE(enetsw_res), | ||
163 | .resource = enetsw_res, | ||
164 | .dev = { | ||
165 | .platform_data = &enetsw_pd, | ||
166 | .dma_mask = &enet_dmamask, | ||
167 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
168 | }, | ||
169 | }; | ||
170 | |||
171 | static int __init register_shared(void) | ||
172 | { | ||
173 | int ret, chan_count; | ||
174 | |||
175 | if (shared_device_registered) | ||
176 | return 0; | ||
177 | |||
178 | bcm63xx_enetdmac_regs_init(); | ||
179 | |||
180 | shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA); | ||
181 | shared_res[0].end = shared_res[0].start; | ||
182 | if (BCMCPU_IS_6345()) | ||
183 | shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1; | ||
184 | else | ||
185 | shared_res[0].end += (RSET_ENETDMA_SIZE) - 1; | ||
186 | |||
187 | if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368()) | ||
188 | chan_count = 32; | ||
189 | else if (BCMCPU_IS_6345()) | ||
190 | chan_count = 8; | ||
191 | else | ||
192 | chan_count = 16; | ||
193 | |||
194 | shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC); | ||
195 | shared_res[1].end = shared_res[1].start; | ||
196 | shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count) - 1; | ||
197 | |||
198 | shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS); | ||
199 | shared_res[2].end = shared_res[2].start; | ||
200 | shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count) - 1; | ||
201 | |||
202 | ret = platform_device_register(&bcm63xx_enet_shared_device); | ||
203 | if (ret) | ||
204 | return ret; | ||
205 | shared_device_registered = 1; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int __init bcm63xx_enet_register(int unit, | ||
211 | const struct bcm63xx_enet_platform_data *pd) | ||
212 | { | ||
213 | struct platform_device *pdev; | ||
214 | struct bcm63xx_enet_platform_data *dpd; | ||
215 | int ret; | ||
216 | |||
217 | if (unit > 1) | ||
218 | return -ENODEV; | ||
219 | |||
220 | if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345())) | ||
221 | return -ENODEV; | ||
222 | |||
223 | ret = register_shared(); | ||
224 | if (ret) | ||
225 | return ret; | ||
226 | |||
227 | if (unit == 0) { | ||
228 | enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0); | ||
229 | enet0_res[0].end = enet0_res[0].start; | ||
230 | enet0_res[0].end += RSET_ENET_SIZE - 1; | ||
231 | enet0_res[1].start = bcm63xx_get_irq_number(IRQ_ENET0); | ||
232 | enet0_res[2].start = bcm63xx_get_irq_number(IRQ_ENET0_RXDMA); | ||
233 | enet0_res[3].start = bcm63xx_get_irq_number(IRQ_ENET0_TXDMA); | ||
234 | pdev = &bcm63xx_enet0_device; | ||
235 | } else { | ||
236 | enet1_res[0].start = bcm63xx_regset_address(RSET_ENET1); | ||
237 | enet1_res[0].end = enet1_res[0].start; | ||
238 | enet1_res[0].end += RSET_ENET_SIZE - 1; | ||
239 | enet1_res[1].start = bcm63xx_get_irq_number(IRQ_ENET1); | ||
240 | enet1_res[2].start = bcm63xx_get_irq_number(IRQ_ENET1_RXDMA); | ||
241 | enet1_res[3].start = bcm63xx_get_irq_number(IRQ_ENET1_TXDMA); | ||
242 | pdev = &bcm63xx_enet1_device; | ||
243 | } | ||
244 | |||
245 | /* copy given platform data */ | ||
246 | dpd = pdev->dev.platform_data; | ||
247 | memcpy(dpd, pd, sizeof(*pd)); | ||
248 | |||
249 | /* adjust them in case internal phy is used */ | ||
250 | if (dpd->use_internal_phy) { | ||
251 | |||
252 | /* internal phy only exists for enet0 */ | ||
253 | if (unit == 1) | ||
254 | return -ENODEV; | ||
255 | |||
256 | dpd->phy_id = 1; | ||
257 | dpd->has_phy_interrupt = 1; | ||
258 | dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY); | ||
259 | } | ||
260 | |||
261 | dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK; | ||
262 | dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK; | ||
263 | if (BCMCPU_IS_6345()) { | ||
264 | dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK; | ||
265 | dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK; | ||
266 | dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK; | ||
267 | dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK; | ||
268 | dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK; | ||
269 | dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH; | ||
270 | dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT; | ||
271 | } else { | ||
272 | dpd->dma_has_sram = true; | ||
273 | dpd->dma_chan_width = ENETDMA_CHAN_WIDTH; | ||
274 | } | ||
275 | |||
276 | if (unit == 0) { | ||
277 | dpd->rx_chan = 0; | ||
278 | dpd->tx_chan = 1; | ||
279 | } else { | ||
280 | dpd->rx_chan = 2; | ||
281 | dpd->tx_chan = 3; | ||
282 | } | ||
283 | |||
284 | ret = platform_device_register(pdev); | ||
285 | if (ret) | ||
286 | return ret; | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | int __init | ||
291 | bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd) | ||
292 | { | ||
293 | int ret; | ||
294 | |||
295 | if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368()) | ||
296 | return -ENODEV; | ||
297 | |||
298 | ret = register_shared(); | ||
299 | if (ret) | ||
300 | return ret; | ||
301 | |||
302 | enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW); | ||
303 | enetsw_res[0].end = enetsw_res[0].start; | ||
304 | enetsw_res[0].end += RSET_ENETSW_SIZE - 1; | ||
305 | enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0); | ||
306 | enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0); | ||
307 | if (!enetsw_res[2].start) | ||
308 | enetsw_res[2].start = -1; | ||
309 | |||
310 | memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd)); | ||
311 | |||
312 | if (BCMCPU_IS_6328()) | ||
313 | enetsw_pd.num_ports = ENETSW_PORTS_6328; | ||
314 | else if (BCMCPU_IS_6362() || BCMCPU_IS_6368()) | ||
315 | enetsw_pd.num_ports = ENETSW_PORTS_6368; | ||
316 | |||
317 | enetsw_pd.dma_has_sram = true; | ||
318 | enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH; | ||
319 | enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK; | ||
320 | enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK; | ||
321 | |||
322 | ret = platform_device_register(&bcm63xx_enetsw_device); | ||
323 | if (ret) | ||
324 | return ret; | ||
325 | |||
326 | return 0; | ||
327 | } | ||