diff options
Diffstat (limited to 'arch/mips/cavium-octeon/octeon-platform.c')
-rw-r--r-- | arch/mips/cavium-octeon/octeon-platform.c | 699 |
1 files changed, 522 insertions, 177 deletions
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index cd61d7281d91..0938df10a71c 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2004-2010 Cavium Networks | 6 | * Copyright (C) 2004-2011 Cavium Networks |
7 | * Copyright (C) 2008 Wind River Systems | 7 | * Copyright (C) 2008 Wind River Systems |
8 | */ | 8 | */ |
9 | 9 | ||
@@ -13,10 +13,16 @@ | |||
13 | #include <linux/usb.h> | 13 | #include <linux/usb.h> |
14 | #include <linux/dma-mapping.h> | 14 | #include <linux/dma-mapping.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | ||
16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/of_fdt.h> | ||
20 | #include <linux/libfdt.h> | ||
17 | 21 | ||
18 | #include <asm/octeon/octeon.h> | 22 | #include <asm/octeon/octeon.h> |
19 | #include <asm/octeon/cvmx-rnm-defs.h> | 23 | #include <asm/octeon/cvmx-rnm-defs.h> |
24 | #include <asm/octeon/cvmx-helper.h> | ||
25 | #include <asm/octeon/cvmx-helper-board.h> | ||
20 | 26 | ||
21 | static struct octeon_cf_data octeon_cf_data; | 27 | static struct octeon_cf_data octeon_cf_data; |
22 | 28 | ||
@@ -162,182 +168,6 @@ out: | |||
162 | } | 168 | } |
163 | device_initcall(octeon_rng_device_init); | 169 | device_initcall(octeon_rng_device_init); |
164 | 170 | ||
165 | static struct i2c_board_info __initdata octeon_i2c_devices[] = { | ||
166 | { | ||
167 | I2C_BOARD_INFO("ds1337", 0x68), | ||
168 | }, | ||
169 | }; | ||
170 | |||
171 | static int __init octeon_i2c_devices_init(void) | ||
172 | { | ||
173 | return i2c_register_board_info(0, octeon_i2c_devices, | ||
174 | ARRAY_SIZE(octeon_i2c_devices)); | ||
175 | } | ||
176 | arch_initcall(octeon_i2c_devices_init); | ||
177 | |||
178 | #define OCTEON_I2C_IO_BASE 0x1180000001000ull | ||
179 | #define OCTEON_I2C_IO_UNIT_OFFSET 0x200 | ||
180 | |||
181 | static struct octeon_i2c_data octeon_i2c_data[2]; | ||
182 | |||
183 | static int __init octeon_i2c_device_init(void) | ||
184 | { | ||
185 | struct platform_device *pd; | ||
186 | int ret = 0; | ||
187 | int port, num_ports; | ||
188 | |||
189 | struct resource i2c_resources[] = { | ||
190 | { | ||
191 | .flags = IORESOURCE_MEM, | ||
192 | }, { | ||
193 | .flags = IORESOURCE_IRQ, | ||
194 | } | ||
195 | }; | ||
196 | |||
197 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
198 | num_ports = 2; | ||
199 | else | ||
200 | num_ports = 1; | ||
201 | |||
202 | for (port = 0; port < num_ports; port++) { | ||
203 | octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate(); | ||
204 | /*FIXME: should be examined. At the moment is set for 100Khz */ | ||
205 | octeon_i2c_data[port].i2c_freq = 100000; | ||
206 | |||
207 | pd = platform_device_alloc("i2c-octeon", port); | ||
208 | if (!pd) { | ||
209 | ret = -ENOMEM; | ||
210 | goto out; | ||
211 | } | ||
212 | |||
213 | pd->dev.platform_data = octeon_i2c_data + port; | ||
214 | |||
215 | i2c_resources[0].start = | ||
216 | OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET); | ||
217 | i2c_resources[0].end = i2c_resources[0].start + 0x1f; | ||
218 | switch (port) { | ||
219 | case 0: | ||
220 | i2c_resources[1].start = OCTEON_IRQ_TWSI; | ||
221 | i2c_resources[1].end = OCTEON_IRQ_TWSI; | ||
222 | break; | ||
223 | case 1: | ||
224 | i2c_resources[1].start = OCTEON_IRQ_TWSI2; | ||
225 | i2c_resources[1].end = OCTEON_IRQ_TWSI2; | ||
226 | break; | ||
227 | default: | ||
228 | BUG(); | ||
229 | } | ||
230 | |||
231 | ret = platform_device_add_resources(pd, | ||
232 | i2c_resources, | ||
233 | ARRAY_SIZE(i2c_resources)); | ||
234 | if (ret) | ||
235 | goto fail; | ||
236 | |||
237 | ret = platform_device_add(pd); | ||
238 | if (ret) | ||
239 | goto fail; | ||
240 | } | ||
241 | return ret; | ||
242 | fail: | ||
243 | platform_device_put(pd); | ||
244 | out: | ||
245 | return ret; | ||
246 | } | ||
247 | device_initcall(octeon_i2c_device_init); | ||
248 | |||
249 | /* Octeon SMI/MDIO interface. */ | ||
250 | static int __init octeon_mdiobus_device_init(void) | ||
251 | { | ||
252 | struct platform_device *pd; | ||
253 | int ret = 0; | ||
254 | |||
255 | if (octeon_is_simulation()) | ||
256 | return 0; /* No mdio in the simulator. */ | ||
257 | |||
258 | /* The bus number is the platform_device id. */ | ||
259 | pd = platform_device_alloc("mdio-octeon", 0); | ||
260 | if (!pd) { | ||
261 | ret = -ENOMEM; | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | ret = platform_device_add(pd); | ||
266 | if (ret) | ||
267 | goto fail; | ||
268 | |||
269 | return ret; | ||
270 | fail: | ||
271 | platform_device_put(pd); | ||
272 | |||
273 | out: | ||
274 | return ret; | ||
275 | |||
276 | } | ||
277 | device_initcall(octeon_mdiobus_device_init); | ||
278 | |||
279 | /* Octeon mgmt port Ethernet interface. */ | ||
280 | static int __init octeon_mgmt_device_init(void) | ||
281 | { | ||
282 | struct platform_device *pd; | ||
283 | int ret = 0; | ||
284 | int port, num_ports; | ||
285 | |||
286 | struct resource mgmt_port_resource = { | ||
287 | .flags = IORESOURCE_IRQ, | ||
288 | .start = -1, | ||
289 | .end = -1 | ||
290 | }; | ||
291 | |||
292 | if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
293 | return 0; | ||
294 | |||
295 | if (OCTEON_IS_MODEL(OCTEON_CN56XX)) | ||
296 | num_ports = 1; | ||
297 | else | ||
298 | num_ports = 2; | ||
299 | |||
300 | for (port = 0; port < num_ports; port++) { | ||
301 | pd = platform_device_alloc("octeon_mgmt", port); | ||
302 | if (!pd) { | ||
303 | ret = -ENOMEM; | ||
304 | goto out; | ||
305 | } | ||
306 | /* No DMA restrictions */ | ||
307 | pd->dev.coherent_dma_mask = DMA_BIT_MASK(64); | ||
308 | pd->dev.dma_mask = &pd->dev.coherent_dma_mask; | ||
309 | |||
310 | switch (port) { | ||
311 | case 0: | ||
312 | mgmt_port_resource.start = OCTEON_IRQ_MII0; | ||
313 | break; | ||
314 | case 1: | ||
315 | mgmt_port_resource.start = OCTEON_IRQ_MII1; | ||
316 | break; | ||
317 | default: | ||
318 | BUG(); | ||
319 | } | ||
320 | mgmt_port_resource.end = mgmt_port_resource.start; | ||
321 | |||
322 | ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); | ||
323 | |||
324 | if (ret) | ||
325 | goto fail; | ||
326 | |||
327 | ret = platform_device_add(pd); | ||
328 | if (ret) | ||
329 | goto fail; | ||
330 | } | ||
331 | return ret; | ||
332 | fail: | ||
333 | platform_device_put(pd); | ||
334 | |||
335 | out: | ||
336 | return ret; | ||
337 | |||
338 | } | ||
339 | device_initcall(octeon_mgmt_device_init); | ||
340 | |||
341 | #ifdef CONFIG_USB | 171 | #ifdef CONFIG_USB |
342 | 172 | ||
343 | static int __init octeon_ehci_device_init(void) | 173 | static int __init octeon_ehci_device_init(void) |
@@ -440,6 +270,521 @@ device_initcall(octeon_ohci_device_init); | |||
440 | 270 | ||
441 | #endif /* CONFIG_USB */ | 271 | #endif /* CONFIG_USB */ |
442 | 272 | ||
273 | static struct of_device_id __initdata octeon_ids[] = { | ||
274 | { .compatible = "simple-bus", }, | ||
275 | { .compatible = "cavium,octeon-6335-uctl", }, | ||
276 | { .compatible = "cavium,octeon-3860-bootbus", }, | ||
277 | { .compatible = "cavium,mdio-mux", }, | ||
278 | { .compatible = "gpio-leds", }, | ||
279 | {}, | ||
280 | }; | ||
281 | |||
282 | static bool __init octeon_has_88e1145(void) | ||
283 | { | ||
284 | return !OCTEON_IS_MODEL(OCTEON_CN52XX) && | ||
285 | !OCTEON_IS_MODEL(OCTEON_CN6XXX) && | ||
286 | !OCTEON_IS_MODEL(OCTEON_CN56XX); | ||
287 | } | ||
288 | |||
289 | static void __init octeon_fdt_set_phy(int eth, int phy_addr) | ||
290 | { | ||
291 | const __be32 *phy_handle; | ||
292 | const __be32 *alt_phy_handle; | ||
293 | const __be32 *reg; | ||
294 | u32 phandle; | ||
295 | int phy; | ||
296 | int alt_phy; | ||
297 | const char *p; | ||
298 | int current_len; | ||
299 | char new_name[20]; | ||
300 | |||
301 | phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL); | ||
302 | if (!phy_handle) | ||
303 | return; | ||
304 | |||
305 | phandle = be32_to_cpup(phy_handle); | ||
306 | phy = fdt_node_offset_by_phandle(initial_boot_params, phandle); | ||
307 | |||
308 | alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); | ||
309 | if (alt_phy_handle) { | ||
310 | u32 alt_phandle = be32_to_cpup(alt_phy_handle); | ||
311 | alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle); | ||
312 | } else { | ||
313 | alt_phy = -1; | ||
314 | } | ||
315 | |||
316 | if (phy_addr < 0 || phy < 0) { | ||
317 | /* Delete the PHY things */ | ||
318 | fdt_nop_property(initial_boot_params, eth, "phy-handle"); | ||
319 | /* This one may fail */ | ||
320 | fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle"); | ||
321 | if (phy >= 0) | ||
322 | fdt_nop_node(initial_boot_params, phy); | ||
323 | if (alt_phy >= 0) | ||
324 | fdt_nop_node(initial_boot_params, alt_phy); | ||
325 | return; | ||
326 | } | ||
327 | |||
328 | if (phy_addr >= 256 && alt_phy > 0) { | ||
329 | const struct fdt_property *phy_prop; | ||
330 | struct fdt_property *alt_prop; | ||
331 | u32 phy_handle_name; | ||
332 | |||
333 | /* Use the alt phy node instead.*/ | ||
334 | phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL); | ||
335 | phy_handle_name = phy_prop->nameoff; | ||
336 | fdt_nop_node(initial_boot_params, phy); | ||
337 | fdt_nop_property(initial_boot_params, eth, "phy-handle"); | ||
338 | alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL); | ||
339 | alt_prop->nameoff = phy_handle_name; | ||
340 | phy = alt_phy; | ||
341 | } | ||
342 | |||
343 | phy_addr &= 0xff; | ||
344 | |||
345 | if (octeon_has_88e1145()) { | ||
346 | fdt_nop_property(initial_boot_params, phy, "marvell,reg-init"); | ||
347 | memset(new_name, 0, sizeof(new_name)); | ||
348 | strcpy(new_name, "marvell,88e1145"); | ||
349 | p = fdt_getprop(initial_boot_params, phy, "compatible", | ||
350 | ¤t_len); | ||
351 | if (p && current_len >= strlen(new_name)) | ||
352 | fdt_setprop_inplace(initial_boot_params, phy, | ||
353 | "compatible", new_name, current_len); | ||
354 | } | ||
355 | |||
356 | reg = fdt_getprop(initial_boot_params, phy, "reg", NULL); | ||
357 | if (phy_addr == be32_to_cpup(reg)) | ||
358 | return; | ||
359 | |||
360 | fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr); | ||
361 | |||
362 | snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr); | ||
363 | |||
364 | p = fdt_get_name(initial_boot_params, phy, ¤t_len); | ||
365 | if (p && current_len == strlen(new_name)) | ||
366 | fdt_set_name(initial_boot_params, phy, new_name); | ||
367 | else | ||
368 | pr_err("Error: could not rename ethernet phy: <%s>", p); | ||
369 | } | ||
370 | |||
371 | static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) | ||
372 | { | ||
373 | u8 new_mac[6]; | ||
374 | u64 mac = *pmac; | ||
375 | int r; | ||
376 | |||
377 | new_mac[0] = (mac >> 40) & 0xff; | ||
378 | new_mac[1] = (mac >> 32) & 0xff; | ||
379 | new_mac[2] = (mac >> 24) & 0xff; | ||
380 | new_mac[3] = (mac >> 16) & 0xff; | ||
381 | new_mac[4] = (mac >> 8) & 0xff; | ||
382 | new_mac[5] = mac & 0xff; | ||
383 | |||
384 | r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address", | ||
385 | new_mac, sizeof(new_mac)); | ||
386 | |||
387 | if (r) { | ||
388 | pr_err("Setting \"local-mac-address\" failed %d", r); | ||
389 | return; | ||
390 | } | ||
391 | *pmac = mac + 1; | ||
392 | } | ||
393 | |||
394 | static void __init octeon_fdt_rm_ethernet(int node) | ||
395 | { | ||
396 | const __be32 *phy_handle; | ||
397 | |||
398 | phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL); | ||
399 | if (phy_handle) { | ||
400 | u32 ph = be32_to_cpup(phy_handle); | ||
401 | int p = fdt_node_offset_by_phandle(initial_boot_params, ph); | ||
402 | if (p >= 0) | ||
403 | fdt_nop_node(initial_boot_params, p); | ||
404 | } | ||
405 | fdt_nop_node(initial_boot_params, node); | ||
406 | } | ||
407 | |||
408 | static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac) | ||
409 | { | ||
410 | char name_buffer[20]; | ||
411 | int eth; | ||
412 | int phy_addr; | ||
413 | int ipd_port; | ||
414 | |||
415 | snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p); | ||
416 | eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer); | ||
417 | if (eth < 0) | ||
418 | return; | ||
419 | if (p > max) { | ||
420 | pr_debug("Deleting port %x:%x\n", i, p); | ||
421 | octeon_fdt_rm_ethernet(eth); | ||
422 | return; | ||
423 | } | ||
424 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
425 | ipd_port = (0x100 * i) + (0x10 * p) + 0x800; | ||
426 | else | ||
427 | ipd_port = 16 * i + p; | ||
428 | |||
429 | phy_addr = cvmx_helper_board_get_mii_address(ipd_port); | ||
430 | octeon_fdt_set_phy(eth, phy_addr); | ||
431 | octeon_fdt_set_mac_addr(eth, pmac); | ||
432 | } | ||
433 | |||
434 | static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) | ||
435 | { | ||
436 | char name_buffer[20]; | ||
437 | int iface; | ||
438 | int p; | ||
439 | int count; | ||
440 | |||
441 | count = cvmx_helper_interface_enumerate(idx); | ||
442 | |||
443 | snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx); | ||
444 | iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer); | ||
445 | if (iface < 0) | ||
446 | return; | ||
447 | |||
448 | for (p = 0; p < 16; p++) | ||
449 | octeon_fdt_pip_port(iface, idx, p, count - 1, pmac); | ||
450 | } | ||
451 | |||
452 | int __init octeon_prune_device_tree(void) | ||
453 | { | ||
454 | int i, max_port, uart_mask; | ||
455 | const char *pip_path; | ||
456 | const char *alias_prop; | ||
457 | char name_buffer[20]; | ||
458 | int aliases; | ||
459 | u64 mac_addr_base; | ||
460 | |||
461 | if (fdt_check_header(initial_boot_params)) | ||
462 | panic("Corrupt Device Tree."); | ||
463 | |||
464 | aliases = fdt_path_offset(initial_boot_params, "/aliases"); | ||
465 | if (aliases < 0) { | ||
466 | pr_err("Error: No /aliases node in device tree."); | ||
467 | return -EINVAL; | ||
468 | } | ||
469 | |||
470 | |||
471 | mac_addr_base = | ||
472 | ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | | ||
473 | ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | | ||
474 | ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | | ||
475 | ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | | ||
476 | ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | | ||
477 | (octeon_bootinfo->mac_addr_base[5] & 0xffull); | ||
478 | |||
479 | if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) | ||
480 | max_port = 2; | ||
481 | else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
482 | max_port = 1; | ||
483 | else | ||
484 | max_port = 0; | ||
485 | |||
486 | if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E) | ||
487 | max_port = 0; | ||
488 | |||
489 | for (i = 0; i < 2; i++) { | ||
490 | int mgmt; | ||
491 | snprintf(name_buffer, sizeof(name_buffer), | ||
492 | "mix%d", i); | ||
493 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
494 | name_buffer, NULL); | ||
495 | if (alias_prop) { | ||
496 | mgmt = fdt_path_offset(initial_boot_params, alias_prop); | ||
497 | if (mgmt < 0) | ||
498 | continue; | ||
499 | if (i >= max_port) { | ||
500 | pr_debug("Deleting mix%d\n", i); | ||
501 | octeon_fdt_rm_ethernet(mgmt); | ||
502 | fdt_nop_property(initial_boot_params, aliases, | ||
503 | name_buffer); | ||
504 | } else { | ||
505 | int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); | ||
506 | octeon_fdt_set_phy(mgmt, phy_addr); | ||
507 | octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | |||
512 | pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL); | ||
513 | if (pip_path) { | ||
514 | int pip = fdt_path_offset(initial_boot_params, pip_path); | ||
515 | if (pip >= 0) | ||
516 | for (i = 0; i <= 4; i++) | ||
517 | octeon_fdt_pip_iface(pip, i, &mac_addr_base); | ||
518 | } | ||
519 | |||
520 | /* I2C */ | ||
521 | if (OCTEON_IS_MODEL(OCTEON_CN52XX) || | ||
522 | OCTEON_IS_MODEL(OCTEON_CN63XX) || | ||
523 | OCTEON_IS_MODEL(OCTEON_CN68XX) || | ||
524 | OCTEON_IS_MODEL(OCTEON_CN56XX)) | ||
525 | max_port = 2; | ||
526 | else | ||
527 | max_port = 1; | ||
528 | |||
529 | for (i = 0; i < 2; i++) { | ||
530 | int i2c; | ||
531 | snprintf(name_buffer, sizeof(name_buffer), | ||
532 | "twsi%d", i); | ||
533 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
534 | name_buffer, NULL); | ||
535 | |||
536 | if (alias_prop) { | ||
537 | i2c = fdt_path_offset(initial_boot_params, alias_prop); | ||
538 | if (i2c < 0) | ||
539 | continue; | ||
540 | if (i >= max_port) { | ||
541 | pr_debug("Deleting twsi%d\n", i); | ||
542 | fdt_nop_node(initial_boot_params, i2c); | ||
543 | fdt_nop_property(initial_boot_params, aliases, | ||
544 | name_buffer); | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | |||
549 | /* SMI/MDIO */ | ||
550 | if (OCTEON_IS_MODEL(OCTEON_CN68XX)) | ||
551 | max_port = 4; | ||
552 | else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || | ||
553 | OCTEON_IS_MODEL(OCTEON_CN63XX) || | ||
554 | OCTEON_IS_MODEL(OCTEON_CN56XX)) | ||
555 | max_port = 2; | ||
556 | else | ||
557 | max_port = 1; | ||
558 | |||
559 | for (i = 0; i < 2; i++) { | ||
560 | int i2c; | ||
561 | snprintf(name_buffer, sizeof(name_buffer), | ||
562 | "smi%d", i); | ||
563 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
564 | name_buffer, NULL); | ||
565 | |||
566 | if (alias_prop) { | ||
567 | i2c = fdt_path_offset(initial_boot_params, alias_prop); | ||
568 | if (i2c < 0) | ||
569 | continue; | ||
570 | if (i >= max_port) { | ||
571 | pr_debug("Deleting smi%d\n", i); | ||
572 | fdt_nop_node(initial_boot_params, i2c); | ||
573 | fdt_nop_property(initial_boot_params, aliases, | ||
574 | name_buffer); | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | |||
579 | /* Serial */ | ||
580 | uart_mask = 3; | ||
581 | |||
582 | /* Right now CN52XX is the only chip with a third uart */ | ||
583 | if (OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
584 | uart_mask |= 4; /* uart2 */ | ||
585 | |||
586 | for (i = 0; i < 3; i++) { | ||
587 | int uart; | ||
588 | snprintf(name_buffer, sizeof(name_buffer), | ||
589 | "uart%d", i); | ||
590 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
591 | name_buffer, NULL); | ||
592 | |||
593 | if (alias_prop) { | ||
594 | uart = fdt_path_offset(initial_boot_params, alias_prop); | ||
595 | if (uart_mask & (1 << i)) | ||
596 | continue; | ||
597 | pr_debug("Deleting uart%d\n", i); | ||
598 | fdt_nop_node(initial_boot_params, uart); | ||
599 | fdt_nop_property(initial_boot_params, aliases, | ||
600 | name_buffer); | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /* Compact Flash */ | ||
605 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
606 | "cf0", NULL); | ||
607 | if (alias_prop) { | ||
608 | union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; | ||
609 | unsigned long base_ptr, region_base, region_size; | ||
610 | unsigned long region1_base = 0; | ||
611 | unsigned long region1_size = 0; | ||
612 | int cs, bootbus; | ||
613 | bool is_16bit = false; | ||
614 | bool is_true_ide = false; | ||
615 | __be32 new_reg[6]; | ||
616 | __be32 *ranges; | ||
617 | int len; | ||
618 | |||
619 | int cf = fdt_path_offset(initial_boot_params, alias_prop); | ||
620 | base_ptr = 0; | ||
621 | if (octeon_bootinfo->major_version == 1 | ||
622 | && octeon_bootinfo->minor_version >= 1) { | ||
623 | if (octeon_bootinfo->compact_flash_common_base_addr) | ||
624 | base_ptr = octeon_bootinfo->compact_flash_common_base_addr; | ||
625 | } else { | ||
626 | base_ptr = 0x1d000800; | ||
627 | } | ||
628 | |||
629 | if (!base_ptr) | ||
630 | goto no_cf; | ||
631 | |||
632 | /* Find CS0 region. */ | ||
633 | for (cs = 0; cs < 8; cs++) { | ||
634 | mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); | ||
635 | region_base = mio_boot_reg_cfg.s.base << 16; | ||
636 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | ||
637 | if (mio_boot_reg_cfg.s.en && base_ptr >= region_base | ||
638 | && base_ptr < region_base + region_size) { | ||
639 | is_16bit = mio_boot_reg_cfg.s.width; | ||
640 | break; | ||
641 | } | ||
642 | } | ||
643 | if (cs >= 7) { | ||
644 | /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */ | ||
645 | goto no_cf; | ||
646 | } | ||
647 | |||
648 | if (!(base_ptr & 0xfffful)) { | ||
649 | /* | ||
650 | * Boot loader signals availability of DMA (true_ide | ||
651 | * mode) by setting low order bits of base_ptr to | ||
652 | * zero. | ||
653 | */ | ||
654 | |||
655 | /* Asume that CS1 immediately follows. */ | ||
656 | mio_boot_reg_cfg.u64 = | ||
657 | cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); | ||
658 | region1_base = mio_boot_reg_cfg.s.base << 16; | ||
659 | region1_size = (mio_boot_reg_cfg.s.size + 1) << 16; | ||
660 | if (!mio_boot_reg_cfg.s.en) | ||
661 | goto no_cf; | ||
662 | is_true_ide = true; | ||
663 | |||
664 | } else { | ||
665 | fdt_nop_property(initial_boot_params, cf, "cavium,true-ide"); | ||
666 | fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle"); | ||
667 | if (!is_16bit) { | ||
668 | __be32 width = cpu_to_be32(8); | ||
669 | fdt_setprop_inplace(initial_boot_params, cf, | ||
670 | "cavium,bus-width", &width, sizeof(width)); | ||
671 | } | ||
672 | } | ||
673 | new_reg[0] = cpu_to_be32(cs); | ||
674 | new_reg[1] = cpu_to_be32(0); | ||
675 | new_reg[2] = cpu_to_be32(0x10000); | ||
676 | new_reg[3] = cpu_to_be32(cs + 1); | ||
677 | new_reg[4] = cpu_to_be32(0); | ||
678 | new_reg[5] = cpu_to_be32(0x10000); | ||
679 | fdt_setprop_inplace(initial_boot_params, cf, | ||
680 | "reg", new_reg, sizeof(new_reg)); | ||
681 | |||
682 | bootbus = fdt_parent_offset(initial_boot_params, cf); | ||
683 | if (bootbus < 0) | ||
684 | goto no_cf; | ||
685 | ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); | ||
686 | if (!ranges || len < (5 * 8 * sizeof(__be32))) | ||
687 | goto no_cf; | ||
688 | |||
689 | ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); | ||
690 | ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); | ||
691 | ranges[(cs * 5) + 4] = cpu_to_be32(region_size); | ||
692 | if (is_true_ide) { | ||
693 | cs++; | ||
694 | ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32); | ||
695 | ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff); | ||
696 | ranges[(cs * 5) + 4] = cpu_to_be32(region1_size); | ||
697 | } | ||
698 | goto end_cf; | ||
699 | no_cf: | ||
700 | fdt_nop_node(initial_boot_params, cf); | ||
701 | |||
702 | end_cf: | ||
703 | ; | ||
704 | } | ||
705 | |||
706 | /* 8 char LED */ | ||
707 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
708 | "led0", NULL); | ||
709 | if (alias_prop) { | ||
710 | union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; | ||
711 | unsigned long base_ptr, region_base, region_size; | ||
712 | int cs, bootbus; | ||
713 | __be32 new_reg[6]; | ||
714 | __be32 *ranges; | ||
715 | int len; | ||
716 | int led = fdt_path_offset(initial_boot_params, alias_prop); | ||
717 | |||
718 | base_ptr = octeon_bootinfo->led_display_base_addr; | ||
719 | if (base_ptr == 0) | ||
720 | goto no_led; | ||
721 | /* Find CS0 region. */ | ||
722 | for (cs = 0; cs < 8; cs++) { | ||
723 | mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); | ||
724 | region_base = mio_boot_reg_cfg.s.base << 16; | ||
725 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | ||
726 | if (mio_boot_reg_cfg.s.en && base_ptr >= region_base | ||
727 | && base_ptr < region_base + region_size) | ||
728 | break; | ||
729 | } | ||
730 | |||
731 | if (cs > 7) | ||
732 | goto no_led; | ||
733 | |||
734 | new_reg[0] = cpu_to_be32(cs); | ||
735 | new_reg[1] = cpu_to_be32(0x20); | ||
736 | new_reg[2] = cpu_to_be32(0x20); | ||
737 | new_reg[3] = cpu_to_be32(cs); | ||
738 | new_reg[4] = cpu_to_be32(0); | ||
739 | new_reg[5] = cpu_to_be32(0x20); | ||
740 | fdt_setprop_inplace(initial_boot_params, led, | ||
741 | "reg", new_reg, sizeof(new_reg)); | ||
742 | |||
743 | bootbus = fdt_parent_offset(initial_boot_params, led); | ||
744 | if (bootbus < 0) | ||
745 | goto no_led; | ||
746 | ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len); | ||
747 | if (!ranges || len < (5 * 8 * sizeof(__be32))) | ||
748 | goto no_led; | ||
749 | |||
750 | ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32); | ||
751 | ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff); | ||
752 | ranges[(cs * 5) + 4] = cpu_to_be32(region_size); | ||
753 | goto end_led; | ||
754 | |||
755 | no_led: | ||
756 | fdt_nop_node(initial_boot_params, led); | ||
757 | end_led: | ||
758 | ; | ||
759 | } | ||
760 | |||
761 | /* OHCI/UHCI USB */ | ||
762 | alias_prop = fdt_getprop(initial_boot_params, aliases, | ||
763 | "uctl", NULL); | ||
764 | if (alias_prop) { | ||
765 | int uctl = fdt_path_offset(initial_boot_params, alias_prop); | ||
766 | |||
767 | if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) || | ||
768 | octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) { | ||
769 | pr_debug("Deleting uctl\n"); | ||
770 | fdt_nop_node(initial_boot_params, uctl); | ||
771 | fdt_nop_property(initial_boot_params, aliases, "uctl"); | ||
772 | } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E || | ||
773 | octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) { | ||
774 | /* Missing "refclk-type" defaults to crystal. */ | ||
775 | fdt_nop_property(initial_boot_params, uctl, "refclk-type"); | ||
776 | } | ||
777 | } | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int __init octeon_publish_devices(void) | ||
783 | { | ||
784 | return of_platform_bus_probe(NULL, octeon_ids, NULL); | ||
785 | } | ||
786 | device_initcall(octeon_publish_devices); | ||
787 | |||
443 | MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); | 788 | MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); |
444 | MODULE_LICENSE("GPL"); | 789 | MODULE_LICENSE("GPL"); |
445 | MODULE_DESCRIPTION("Platform driver for Octeon SOC"); | 790 | MODULE_DESCRIPTION("Platform driver for Octeon SOC"); |