linux/arch/mips/cavium-octeon/octeon-platform.c
<<
>>
Prefs
   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
  27static struct octeon_cf_data octeon_cf_data;
  28
  29static 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;
 122fail:
 123        platform_device_put(pd);
 124out:
 125        return ret;
 126}
 127device_initcall(octeon_cf_device_init);
 128
 129/* Octeon Random Number Generator.  */
 130static 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;
 163fail:
 164        platform_device_put(pd);
 165
 166out:
 167        return ret;
 168}
 169device_initcall(octeon_rng_device_init);
 170
 171#ifdef CONFIG_USB
 172
 173static 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;
 215fail:
 216        platform_device_put(pd);
 217out:
 218        return ret;
 219}
 220device_initcall(octeon_ehci_device_init);
 221
 222static 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;
 264fail:
 265        platform_device_put(pd);
 266out:
 267        return ret;
 268}
 269device_initcall(octeon_ohci_device_init);
 270
 271#endif /* CONFIG_USB */
 272
 273static 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
 282static 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
 289static 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                                &current_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, &current_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
 371static 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
 394static 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
 408static 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
 434static 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
 452int __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;
 699no_cf:
 700                fdt_nop_node(initial_boot_params, cf);
 701
 702end_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
 755no_led:
 756                fdt_nop_node(initial_boot_params, led);
 757end_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
 782static int __init octeon_publish_devices(void)
 783{
 784        return of_platform_bus_probe(NULL, octeon_ids, NULL);
 785}
 786device_initcall(octeon_publish_devices);
 787
 788MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 789MODULE_LICENSE("GPL");
 790MODULE_DESCRIPTION("Platform driver for Octeon SOC");
 791