netdev: octeon_mgmt: Convert to use device tree.
[linux-3.10.git] / arch / mips / cavium-octeon / octeon-platform.c
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                                 &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
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");