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