diff options
Diffstat (limited to 'arch/powerpc/sysdev/fsl_soc.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 241 |
1 files changed, 28 insertions, 213 deletions
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 26ecb96f9731..115cb16351fd 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -207,236 +207,51 @@ static int __init of_add_fixed_phys(void) | |||
207 | arch_initcall(of_add_fixed_phys); | 207 | arch_initcall(of_add_fixed_phys); |
208 | #endif /* CONFIG_FIXED_PHY */ | 208 | #endif /* CONFIG_FIXED_PHY */ |
209 | 209 | ||
210 | static int gfar_mdio_of_init_one(struct device_node *np) | 210 | #ifdef CONFIG_PPC_83xx |
211 | { | 211 | static int __init mpc83xx_wdt_init(void) |
212 | int k; | ||
213 | struct device_node *child = NULL; | ||
214 | struct gianfar_mdio_data mdio_data; | ||
215 | struct platform_device *mdio_dev; | ||
216 | struct resource res; | ||
217 | int ret; | ||
218 | |||
219 | memset(&res, 0, sizeof(res)); | ||
220 | memset(&mdio_data, 0, sizeof(mdio_data)); | ||
221 | |||
222 | ret = of_address_to_resource(np, 0, &res); | ||
223 | if (ret) | ||
224 | return ret; | ||
225 | |||
226 | /* The gianfar device will try to use the same ID created below to find | ||
227 | * this bus, to coordinate register access (since they share). */ | ||
228 | mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", | ||
229 | res.start&0xfffff, &res, 1); | ||
230 | if (IS_ERR(mdio_dev)) | ||
231 | return PTR_ERR(mdio_dev); | ||
232 | |||
233 | for (k = 0; k < 32; k++) | ||
234 | mdio_data.irq[k] = PHY_POLL; | ||
235 | |||
236 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
237 | int irq = irq_of_parse_and_map(child, 0); | ||
238 | if (irq != NO_IRQ) { | ||
239 | const u32 *id = of_get_property(child, "reg", NULL); | ||
240 | mdio_data.irq[*id] = irq; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | ret = platform_device_add_data(mdio_dev, &mdio_data, | ||
245 | sizeof(struct gianfar_mdio_data)); | ||
246 | if (ret) | ||
247 | platform_device_unregister(mdio_dev); | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static int __init gfar_mdio_of_init(void) | ||
253 | { | ||
254 | struct device_node *np = NULL; | ||
255 | |||
256 | for_each_compatible_node(np, NULL, "fsl,gianfar-mdio") | ||
257 | gfar_mdio_of_init_one(np); | ||
258 | |||
259 | /* try the deprecated version */ | ||
260 | for_each_compatible_node(np, "mdio", "gianfar"); | ||
261 | gfar_mdio_of_init_one(np); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | arch_initcall(gfar_mdio_of_init); | ||
267 | |||
268 | static const char *gfar_tx_intr = "tx"; | ||
269 | static const char *gfar_rx_intr = "rx"; | ||
270 | static const char *gfar_err_intr = "error"; | ||
271 | |||
272 | static int __init gfar_of_init(void) | ||
273 | { | 212 | { |
213 | struct resource r; | ||
274 | struct device_node *np; | 214 | struct device_node *np; |
275 | unsigned int i; | 215 | struct platform_device *dev; |
276 | struct platform_device *gfar_dev; | 216 | u32 freq = fsl_get_sys_freq(); |
277 | struct resource res; | ||
278 | int ret; | 217 | int ret; |
279 | 218 | ||
280 | for (np = NULL, i = 0; | 219 | np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt"); |
281 | (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; | ||
282 | i++) { | ||
283 | struct resource r[4]; | ||
284 | struct device_node *phy, *mdio; | ||
285 | struct gianfar_platform_data gfar_data; | ||
286 | const unsigned int *id; | ||
287 | const char *model; | ||
288 | const char *ctype; | ||
289 | const void *mac_addr; | ||
290 | const phandle *ph; | ||
291 | int n_res = 2; | ||
292 | |||
293 | if (!of_device_is_available(np)) | ||
294 | continue; | ||
295 | |||
296 | memset(r, 0, sizeof(r)); | ||
297 | memset(&gfar_data, 0, sizeof(gfar_data)); | ||
298 | |||
299 | ret = of_address_to_resource(np, 0, &r[0]); | ||
300 | if (ret) | ||
301 | goto err; | ||
302 | |||
303 | of_irq_to_resource(np, 0, &r[1]); | ||
304 | |||
305 | model = of_get_property(np, "model", NULL); | ||
306 | |||
307 | /* If we aren't the FEC we have multiple interrupts */ | ||
308 | if (model && strcasecmp(model, "FEC")) { | ||
309 | r[1].name = gfar_tx_intr; | ||
310 | |||
311 | r[2].name = gfar_rx_intr; | ||
312 | of_irq_to_resource(np, 1, &r[2]); | ||
313 | 220 | ||
314 | r[3].name = gfar_err_intr; | 221 | if (!np) { |
315 | of_irq_to_resource(np, 2, &r[3]); | 222 | ret = -ENODEV; |
316 | 223 | goto nodev; | |
317 | n_res += 2; | 224 | } |
318 | } | ||
319 | |||
320 | gfar_dev = | ||
321 | platform_device_register_simple("fsl-gianfar", i, &r[0], | ||
322 | n_res); | ||
323 | |||
324 | if (IS_ERR(gfar_dev)) { | ||
325 | ret = PTR_ERR(gfar_dev); | ||
326 | goto err; | ||
327 | } | ||
328 | |||
329 | mac_addr = of_get_mac_address(np); | ||
330 | if (mac_addr) | ||
331 | memcpy(gfar_data.mac_addr, mac_addr, 6); | ||
332 | |||
333 | if (model && !strcasecmp(model, "TSEC")) | ||
334 | gfar_data.device_flags = | ||
335 | FSL_GIANFAR_DEV_HAS_GIGABIT | | ||
336 | FSL_GIANFAR_DEV_HAS_COALESCE | | ||
337 | FSL_GIANFAR_DEV_HAS_RMON | | ||
338 | FSL_GIANFAR_DEV_HAS_MULTI_INTR; | ||
339 | if (model && !strcasecmp(model, "eTSEC")) | ||
340 | gfar_data.device_flags = | ||
341 | FSL_GIANFAR_DEV_HAS_GIGABIT | | ||
342 | FSL_GIANFAR_DEV_HAS_COALESCE | | ||
343 | FSL_GIANFAR_DEV_HAS_RMON | | ||
344 | FSL_GIANFAR_DEV_HAS_MULTI_INTR | | ||
345 | FSL_GIANFAR_DEV_HAS_CSUM | | ||
346 | FSL_GIANFAR_DEV_HAS_VLAN | | ||
347 | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; | ||
348 | |||
349 | ctype = of_get_property(np, "phy-connection-type", NULL); | ||
350 | |||
351 | /* We only care about rgmii-id. The rest are autodetected */ | ||
352 | if (ctype && !strcmp(ctype, "rgmii-id")) | ||
353 | gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID; | ||
354 | else | ||
355 | gfar_data.interface = PHY_INTERFACE_MODE_MII; | ||
356 | |||
357 | if (of_get_property(np, "fsl,magic-packet", NULL)) | ||
358 | gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; | ||
359 | |||
360 | ph = of_get_property(np, "phy-handle", NULL); | ||
361 | if (ph == NULL) { | ||
362 | u32 *fixed_link; | ||
363 | |||
364 | fixed_link = (u32 *)of_get_property(np, "fixed-link", | ||
365 | NULL); | ||
366 | if (!fixed_link) { | ||
367 | ret = -ENODEV; | ||
368 | goto unreg; | ||
369 | } | ||
370 | |||
371 | snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0"); | ||
372 | gfar_data.phy_id = fixed_link[0]; | ||
373 | } else { | ||
374 | phy = of_find_node_by_phandle(*ph); | ||
375 | |||
376 | if (phy == NULL) { | ||
377 | ret = -ENODEV; | ||
378 | goto unreg; | ||
379 | } | ||
380 | |||
381 | mdio = of_get_parent(phy); | ||
382 | |||
383 | id = of_get_property(phy, "reg", NULL); | ||
384 | ret = of_address_to_resource(mdio, 0, &res); | ||
385 | if (ret) { | ||
386 | of_node_put(phy); | ||
387 | of_node_put(mdio); | ||
388 | goto unreg; | ||
389 | } | ||
390 | |||
391 | gfar_data.phy_id = *id; | ||
392 | snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx", | ||
393 | (unsigned long long)res.start&0xfffff); | ||
394 | 225 | ||
395 | of_node_put(phy); | 226 | memset(&r, 0, sizeof(r)); |
396 | of_node_put(mdio); | ||
397 | } | ||
398 | 227 | ||
399 | /* Get MDIO bus controlled by this eTSEC, if any. Normally only | 228 | ret = of_address_to_resource(np, 0, &r); |
400 | * eTSEC 1 will control an MDIO bus, not necessarily the same | 229 | if (ret) |
401 | * bus that its PHY is on ('mdio' above), so we can't just use | 230 | goto err; |
402 | * that. What we do is look for a gianfar mdio device that has | ||
403 | * overlapping registers with this device. That's really the | ||
404 | * whole point, to find the device sharing our registers to | ||
405 | * coordinate access with it. | ||
406 | */ | ||
407 | for_each_compatible_node(mdio, NULL, "fsl,gianfar-mdio") { | ||
408 | if (of_address_to_resource(mdio, 0, &res)) | ||
409 | continue; | ||
410 | |||
411 | if (res.start >= r[0].start && res.end <= r[0].end) { | ||
412 | /* Get the ID the mdio bus platform device was | ||
413 | * registered with. gfar_data.bus_id is | ||
414 | * different because it's for finding a PHY, | ||
415 | * while this is for finding a MII bus. | ||
416 | */ | ||
417 | gfar_data.mdio_bus = res.start&0xfffff; | ||
418 | of_node_put(mdio); | ||
419 | break; | ||
420 | } | ||
421 | } | ||
422 | 231 | ||
423 | ret = | 232 | dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1); |
424 | platform_device_add_data(gfar_dev, &gfar_data, | 233 | if (IS_ERR(dev)) { |
425 | sizeof(struct | 234 | ret = PTR_ERR(dev); |
426 | gianfar_platform_data)); | 235 | goto err; |
427 | if (ret) | ||
428 | goto unreg; | ||
429 | } | 236 | } |
430 | 237 | ||
238 | ret = platform_device_add_data(dev, &freq, sizeof(freq)); | ||
239 | if (ret) | ||
240 | goto unreg; | ||
241 | |||
242 | of_node_put(np); | ||
431 | return 0; | 243 | return 0; |
432 | 244 | ||
433 | unreg: | 245 | unreg: |
434 | platform_device_unregister(gfar_dev); | 246 | platform_device_unregister(dev); |
435 | err: | 247 | err: |
248 | of_node_put(np); | ||
249 | nodev: | ||
436 | return ret; | 250 | return ret; |
437 | } | 251 | } |
438 | 252 | ||
439 | arch_initcall(gfar_of_init); | 253 | arch_initcall(mpc83xx_wdt_init); |
254 | #endif | ||
440 | 255 | ||
441 | static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) | 256 | static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) |
442 | { | 257 | { |