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) 2004-2011 Cavium Networks 7 * Copyright (C) 2008 Wind River Systems 8 */ 9 10 #include <linux/init.h> 11 #include <linux/irq.h> 12 #include <linux/i2c.h> 13 #include <linux/usb.h> 14 #include <linux/dma-mapping.h> 15 #include <linux/module.h> 16 #include <linux/slab.h> 17 #include <linux/platform_device.h> 18 #include <linux/of_platform.h> 19 #include <linux/of_fdt.h> 20 #include <linux/libfdt.h> 21 22 #include <asm/octeon/octeon.h> 23 #include <asm/octeon/cvmx-rnm-defs.h> 24 #include <asm/octeon/cvmx-helper.h> 25 #include <asm/octeon/cvmx-helper-board.h> 26 27 static struct octeon_cf_data octeon_cf_data; 28 29 static int __init octeon_cf_device_init(void) 30 { 31 union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; 32 unsigned long base_ptr, region_base, region_size; 33 struct platform_device *pd; 34 struct resource cf_resources[3]; 35 unsigned int num_resources; 36 int i; 37 int ret = 0; 38 39 /* Setup octeon-cf platform device if present. */ 40 base_ptr = 0; 41 if (octeon_bootinfo->major_version == 1 42 && octeon_bootinfo->minor_version >= 1) { 43 if (octeon_bootinfo->compact_flash_common_base_addr) 44 base_ptr = 45 octeon_bootinfo->compact_flash_common_base_addr; 46 } else { 47 base_ptr = 0x1d000800; 48 } 49 50 if (!base_ptr) 51 return ret; 52 53 /* Find CS0 region. */ 54 for (i = 0; i < 8; i++) { 55 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); 56 region_base = mio_boot_reg_cfg.s.base << 16; 57 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 58 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base 59 && base_ptr < region_base + region_size) 60 break; 61 } 62 if (i >= 7) { 63 /* i and i + 1 are CS0 and CS1, both must be less than 8. */ 64 goto out; 65 } 66 octeon_cf_data.base_region = i; 67 octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; 68 octeon_cf_data.base_region_bias = base_ptr - region_base; 69 memset(cf_resources, 0, sizeof(cf_resources)); 70 num_resources = 0; 71 cf_resources[num_resources].flags = IORESOURCE_MEM; 72 cf_resources[num_resources].start = region_base; 73 cf_resources[num_resources].end = region_base + region_size - 1; 74 num_resources++; 75 76 77 if (!(base_ptr & 0xfffful)) { 78 /* 79 * Boot loader signals availability of DMA (true_ide 80 * mode) by setting low order bits of base_ptr to 81 * zero. 82 */ 83 84 /* Assume that CS1 immediately follows. */ 85 mio_boot_reg_cfg.u64 = 86 cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); 87 region_base = mio_boot_reg_cfg.s.base << 16; 88 region_size = (mio_boot_reg_cfg.s.size + 1) << 16; 89 if (!mio_boot_reg_cfg.s.en) 90 goto out; 91 92 cf_resources[num_resources].flags = IORESOURCE_MEM; 93 cf_resources[num_resources].start = region_base; 94 cf_resources[num_resources].end = region_base + region_size - 1; 95 num_resources++; 96 97 octeon_cf_data.dma_engine = 0; 98 cf_resources[num_resources].flags = IORESOURCE_IRQ; 99 cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; 100 cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; 101 num_resources++; 102 } else { 103 octeon_cf_data.dma_engine = -1; 104 } 105 106 pd = platform_device_alloc("pata_octeon_cf", -1); 107 if (!pd) { 108 ret = -ENOMEM; 109 goto out; 110 } 111 pd->dev.platform_data = &octeon_cf_data; 112 113 ret = platform_device_add_resources(pd, cf_resources, num_resources); 114 if (ret) 115 goto fail; 116 117 ret = platform_device_add(pd); 118 if (ret) 119 goto fail; 120 121 return ret; 122 fail: 123 platform_device_put(pd); 124 out: 125 return ret; 126 } 127 device_initcall(octeon_cf_device_init); 128 129 /* Octeon Random Number Generator. */ 130 static int __init octeon_rng_device_init(void) 131 { 132 struct platform_device *pd; 133 int ret = 0; 134 135 struct resource rng_resources[] = { 136 { 137 .flags = IORESOURCE_MEM, 138 .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), 139 .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf 140 }, { 141 .flags = IORESOURCE_MEM, 142 .start = cvmx_build_io_address(8, 0), 143 .end = cvmx_build_io_address(8, 0) + 0x7 144 } 145 }; 146 147 pd = platform_device_alloc("octeon_rng", -1); 148 if (!pd) { 149 ret = -ENOMEM; 150 goto out; 151 } 152 153 ret = platform_device_add_resources(pd, rng_resources, 154 ARRAY_SIZE(rng_resources)); 155 if (ret) 156 goto fail; 157 158 ret = platform_device_add(pd); 159 if (ret) 160 goto fail; 161 162 return ret; 163 fail: 164 platform_device_put(pd); 165 166 out: 167 return ret; 168 } 169 device_initcall(octeon_rng_device_init); 170 171 #ifdef CONFIG_USB 172 173 static int __init octeon_ehci_device_init(void) 174 { 175 struct platform_device *pd; 176 int ret = 0; 177 178 struct resource usb_resources[] = { 179 { 180 .flags = IORESOURCE_MEM, 181 }, { 182 .flags = IORESOURCE_IRQ, 183 } 184 }; 185 186 /* Only Octeon2 has ehci/ohci */ 187 if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) 188 return 0; 189 190 if (octeon_is_simulation() || usb_disabled()) 191 return 0; /* No USB in the simulator. */ 192 193 pd = platform_device_alloc("octeon-ehci", 0); 194 if (!pd) { 195 ret = -ENOMEM; 196 goto out; 197 } 198 199 usb_resources[0].start = 0x00016F0000000000ULL; 200 usb_resources[0].end = usb_resources[0].start + 0x100; 201 202 usb_resources[1].start = OCTEON_IRQ_USB0; 203 usb_resources[1].end = OCTEON_IRQ_USB0; 204 205 ret = platform_device_add_resources(pd, usb_resources, 206 ARRAY_SIZE(usb_resources)); 207 if (ret) 208 goto fail; 209 210 ret = platform_device_add(pd); 211 if (ret) 212 goto fail; 213 214 return ret; 215 fail: 216 platform_device_put(pd); 217 out: 218 return ret; 219 } 220 device_initcall(octeon_ehci_device_init); 221 222 static int __init octeon_ohci_device_init(void) 223 { 224 struct platform_device *pd; 225 int ret = 0; 226 227 struct resource usb_resources[] = { 228 { 229 .flags = IORESOURCE_MEM, 230 }, { 231 .flags = IORESOURCE_IRQ, 232 } 233 }; 234 235 /* Only Octeon2 has ehci/ohci */ 236 if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) 237 return 0; 238 239 if (octeon_is_simulation() || usb_disabled()) 240 return 0; /* No USB in the simulator. */ 241 242 pd = platform_device_alloc("octeon-ohci", 0); 243 if (!pd) { 244 ret = -ENOMEM; 245 goto out; 246 } 247 248 usb_resources[0].start = 0x00016F0000000400ULL; 249 usb_resources[0].end = usb_resources[0].start + 0x100; 250 251 usb_resources[1].start = OCTEON_IRQ_USB0; 252 usb_resources[1].end = OCTEON_IRQ_USB0; 253 254 ret = platform_device_add_resources(pd, usb_resources, 255 ARRAY_SIZE(usb_resources)); 256 if (ret) 257 goto fail; 258 259 ret = platform_device_add(pd); 260 if (ret) 261 goto fail; 262 263 return ret; 264 fail: 265 platform_device_put(pd); 266 out: 267 return ret; 268 } 269 device_initcall(octeon_ohci_device_init); 270 271 #endif /* CONFIG_USB */ 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 788 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); 789 MODULE_LICENSE("GPL"); 790 MODULE_DESCRIPTION("Platform driver for Octeon SOC"); 791