blob: 2754bc225903c073c0909a5db83e38c20e87123b [file] [log] [blame]
David Daney512254b2009-09-16 14:54:18 -07001/*
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 *
David Daney7ed18152012-07-05 18:12:38 +02006 * Copyright (C) 2004-2011 Cavium Networks
David Daney512254b2009-09-16 14:54:18 -07007 * Copyright (C) 2008 Wind River Systems
8 */
9
10#include <linux/init.h>
11#include <linux/irq.h>
David Daneyd9577052010-01-07 11:54:21 -080012#include <linux/i2c.h>
David Daney340fbb82010-10-08 14:47:53 -070013#include <linux/usb.h>
David Daneyf1299072010-10-01 13:27:27 -070014#include <linux/dma-mapping.h>
David Daney512254b2009-09-16 14:54:18 -070015#include <linux/module.h>
David Daney7ed18152012-07-05 18:12:38 +020016#include <linux/slab.h>
David Daney512254b2009-09-16 14:54:18 -070017#include <linux/platform_device.h>
David Daney7ed18152012-07-05 18:12:38 +020018#include <linux/of_platform.h>
19#include <linux/of_fdt.h>
20#include <linux/libfdt.h>
David Daney512254b2009-09-16 14:54:18 -070021
22#include <asm/octeon/octeon.h>
23#include <asm/octeon/cvmx-rnm-defs.h>
David Daney7ed18152012-07-05 18:12:38 +020024#include <asm/octeon/cvmx-helper.h>
25#include <asm/octeon/cvmx-helper-board.h>
David Daney512254b2009-09-16 14:54:18 -070026
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
Lucas De Marchi25985ed2011-03-30 22:57:33 -030084 /* Assume that CS1 immediately follows. */
David Daney512254b2009-09-16 14:54:18 -070085 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
David Daneyd9577052010-01-07 11:54:21 -0800171static struct i2c_board_info __initdata octeon_i2c_devices[] = {
172 {
173 I2C_BOARD_INFO("ds1337", 0x68),
174 },
175};
176
177static int __init octeon_i2c_devices_init(void)
178{
179 return i2c_register_board_info(0, octeon_i2c_devices,
180 ARRAY_SIZE(octeon_i2c_devices));
181}
182arch_initcall(octeon_i2c_devices_init);
David Daneyf41c3c12010-01-07 13:23:41 -0800183
184#define OCTEON_I2C_IO_BASE 0x1180000001000ull
185#define OCTEON_I2C_IO_UNIT_OFFSET 0x200
186
187static struct octeon_i2c_data octeon_i2c_data[2];
188
189static int __init octeon_i2c_device_init(void)
190{
191 struct platform_device *pd;
192 int ret = 0;
193 int port, num_ports;
194
195 struct resource i2c_resources[] = {
196 {
197 .flags = IORESOURCE_MEM,
198 }, {
199 .flags = IORESOURCE_IRQ,
200 }
201 };
202
203 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
204 num_ports = 2;
205 else
206 num_ports = 1;
207
208 for (port = 0; port < num_ports; port++) {
David Daney4b8bca72010-10-07 16:03:50 -0700209 octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate();
David Daneyf41c3c12010-01-07 13:23:41 -0800210 /*FIXME: should be examined. At the moment is set for 100Khz */
211 octeon_i2c_data[port].i2c_freq = 100000;
212
213 pd = platform_device_alloc("i2c-octeon", port);
214 if (!pd) {
215 ret = -ENOMEM;
216 goto out;
217 }
218
219 pd->dev.platform_data = octeon_i2c_data + port;
220
221 i2c_resources[0].start =
222 OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET);
223 i2c_resources[0].end = i2c_resources[0].start + 0x1f;
224 switch (port) {
225 case 0:
226 i2c_resources[1].start = OCTEON_IRQ_TWSI;
227 i2c_resources[1].end = OCTEON_IRQ_TWSI;
228 break;
229 case 1:
230 i2c_resources[1].start = OCTEON_IRQ_TWSI2;
231 i2c_resources[1].end = OCTEON_IRQ_TWSI2;
232 break;
233 default:
234 BUG();
235 }
236
237 ret = platform_device_add_resources(pd,
238 i2c_resources,
239 ARRAY_SIZE(i2c_resources));
240 if (ret)
241 goto fail;
242
243 ret = platform_device_add(pd);
244 if (ret)
245 goto fail;
246 }
247 return ret;
248fail:
249 platform_device_put(pd);
250out:
251 return ret;
252}
253device_initcall(octeon_i2c_device_init);
254
David Daney0f7e64a2009-10-14 12:04:37 -0700255/* Octeon SMI/MDIO interface. */
256static int __init octeon_mdiobus_device_init(void)
257{
258 struct platform_device *pd;
259 int ret = 0;
260
261 if (octeon_is_simulation())
262 return 0; /* No mdio in the simulator. */
263
264 /* The bus number is the platform_device id. */
265 pd = platform_device_alloc("mdio-octeon", 0);
266 if (!pd) {
267 ret = -ENOMEM;
268 goto out;
269 }
270
271 ret = platform_device_add(pd);
272 if (ret)
273 goto fail;
274
275 return ret;
276fail:
277 platform_device_put(pd);
278
279out:
280 return ret;
281
282}
283device_initcall(octeon_mdiobus_device_init);
284
David Daney24479d92009-10-14 12:04:39 -0700285/* Octeon mgmt port Ethernet interface. */
286static int __init octeon_mgmt_device_init(void)
287{
288 struct platform_device *pd;
289 int ret = 0;
290 int port, num_ports;
291
292 struct resource mgmt_port_resource = {
293 .flags = IORESOURCE_IRQ,
294 .start = -1,
295 .end = -1
296 };
297
298 if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
299 return 0;
300
301 if (OCTEON_IS_MODEL(OCTEON_CN56XX))
302 num_ports = 1;
303 else
304 num_ports = 2;
305
306 for (port = 0; port < num_ports; port++) {
307 pd = platform_device_alloc("octeon_mgmt", port);
308 if (!pd) {
309 ret = -ENOMEM;
310 goto out;
311 }
David Daneyf1299072010-10-01 13:27:27 -0700312 /* No DMA restrictions */
313 pd->dev.coherent_dma_mask = DMA_BIT_MASK(64);
314 pd->dev.dma_mask = &pd->dev.coherent_dma_mask;
315
David Daney24479d92009-10-14 12:04:39 -0700316 switch (port) {
317 case 0:
318 mgmt_port_resource.start = OCTEON_IRQ_MII0;
319 break;
320 case 1:
321 mgmt_port_resource.start = OCTEON_IRQ_MII1;
322 break;
323 default:
324 BUG();
325 }
326 mgmt_port_resource.end = mgmt_port_resource.start;
327
328 ret = platform_device_add_resources(pd, &mgmt_port_resource, 1);
329
330 if (ret)
331 goto fail;
332
333 ret = platform_device_add(pd);
334 if (ret)
335 goto fail;
336 }
337 return ret;
338fail:
339 platform_device_put(pd);
340
341out:
342 return ret;
343
344}
345device_initcall(octeon_mgmt_device_init);
346
David Daney340fbb82010-10-08 14:47:53 -0700347#ifdef CONFIG_USB
348
349static int __init octeon_ehci_device_init(void)
350{
351 struct platform_device *pd;
352 int ret = 0;
353
354 struct resource usb_resources[] = {
355 {
356 .flags = IORESOURCE_MEM,
357 }, {
358 .flags = IORESOURCE_IRQ,
359 }
360 };
361
362 /* Only Octeon2 has ehci/ohci */
363 if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
364 return 0;
365
366 if (octeon_is_simulation() || usb_disabled())
367 return 0; /* No USB in the simulator. */
368
369 pd = platform_device_alloc("octeon-ehci", 0);
370 if (!pd) {
371 ret = -ENOMEM;
372 goto out;
373 }
374
375 usb_resources[0].start = 0x00016F0000000000ULL;
376 usb_resources[0].end = usb_resources[0].start + 0x100;
377
378 usb_resources[1].start = OCTEON_IRQ_USB0;
379 usb_resources[1].end = OCTEON_IRQ_USB0;
380
381 ret = platform_device_add_resources(pd, usb_resources,
382 ARRAY_SIZE(usb_resources));
383 if (ret)
384 goto fail;
385
386 ret = platform_device_add(pd);
387 if (ret)
388 goto fail;
389
390 return ret;
391fail:
392 platform_device_put(pd);
393out:
394 return ret;
395}
396device_initcall(octeon_ehci_device_init);
397
398static int __init octeon_ohci_device_init(void)
399{
400 struct platform_device *pd;
401 int ret = 0;
402
403 struct resource usb_resources[] = {
404 {
405 .flags = IORESOURCE_MEM,
406 }, {
407 .flags = IORESOURCE_IRQ,
408 }
409 };
410
411 /* Only Octeon2 has ehci/ohci */
412 if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
413 return 0;
414
415 if (octeon_is_simulation() || usb_disabled())
416 return 0; /* No USB in the simulator. */
417
418 pd = platform_device_alloc("octeon-ohci", 0);
419 if (!pd) {
420 ret = -ENOMEM;
421 goto out;
422 }
423
424 usb_resources[0].start = 0x00016F0000000400ULL;
425 usb_resources[0].end = usb_resources[0].start + 0x100;
426
427 usb_resources[1].start = OCTEON_IRQ_USB0;
428 usb_resources[1].end = OCTEON_IRQ_USB0;
429
430 ret = platform_device_add_resources(pd, usb_resources,
431 ARRAY_SIZE(usb_resources));
432 if (ret)
433 goto fail;
434
435 ret = platform_device_add(pd);
436 if (ret)
437 goto fail;
438
439 return ret;
440fail:
441 platform_device_put(pd);
442out:
443 return ret;
444}
445device_initcall(octeon_ohci_device_init);
446
447#endif /* CONFIG_USB */
448
David Daney7ed18152012-07-05 18:12:38 +0200449static struct of_device_id __initdata octeon_ids[] = {
450 { .compatible = "simple-bus", },
451 { .compatible = "cavium,octeon-6335-uctl", },
452 { .compatible = "cavium,octeon-3860-bootbus", },
453 { .compatible = "cavium,mdio-mux", },
454 { .compatible = "gpio-leds", },
455 {},
456};
457
458static bool __init octeon_has_88e1145(void)
459{
460 return !OCTEON_IS_MODEL(OCTEON_CN52XX) &&
461 !OCTEON_IS_MODEL(OCTEON_CN6XXX) &&
462 !OCTEON_IS_MODEL(OCTEON_CN56XX);
463}
464
465static void __init octeon_fdt_set_phy(int eth, int phy_addr)
466{
467 const __be32 *phy_handle;
468 const __be32 *alt_phy_handle;
469 const __be32 *reg;
470 u32 phandle;
471 int phy;
472 int alt_phy;
473 const char *p;
474 int current_len;
475 char new_name[20];
476
477 phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL);
478 if (!phy_handle)
479 return;
480
481 phandle = be32_to_cpup(phy_handle);
482 phy = fdt_node_offset_by_phandle(initial_boot_params, phandle);
483
484 alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL);
485 if (alt_phy_handle) {
486 u32 alt_phandle = be32_to_cpup(alt_phy_handle);
487 alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle);
488 } else {
489 alt_phy = -1;
490 }
491
492 if (phy_addr < 0 || phy < 0) {
493 /* Delete the PHY things */
494 fdt_nop_property(initial_boot_params, eth, "phy-handle");
495 /* This one may fail */
496 fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle");
497 if (phy >= 0)
498 fdt_nop_node(initial_boot_params, phy);
499 if (alt_phy >= 0)
500 fdt_nop_node(initial_boot_params, alt_phy);
501 return;
502 }
503
504 if (phy_addr >= 256 && alt_phy > 0) {
505 const struct fdt_property *phy_prop;
506 struct fdt_property *alt_prop;
507 u32 phy_handle_name;
508
509 /* Use the alt phy node instead.*/
510 phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL);
511 phy_handle_name = phy_prop->nameoff;
512 fdt_nop_node(initial_boot_params, phy);
513 fdt_nop_property(initial_boot_params, eth, "phy-handle");
514 alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL);
515 alt_prop->nameoff = phy_handle_name;
516 phy = alt_phy;
517 }
518
519 phy_addr &= 0xff;
520
521 if (octeon_has_88e1145()) {
522 fdt_nop_property(initial_boot_params, phy, "marvell,reg-init");
523 memset(new_name, 0, sizeof(new_name));
524 strcpy(new_name, "marvell,88e1145");
525 p = fdt_getprop(initial_boot_params, phy, "compatible",
526 &current_len);
527 if (p && current_len >= strlen(new_name))
528 fdt_setprop_inplace(initial_boot_params, phy,
529 "compatible", new_name, current_len);
530 }
531
532 reg = fdt_getprop(initial_boot_params, phy, "reg", NULL);
533 if (phy_addr == be32_to_cpup(reg))
534 return;
535
536 fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr);
537
538 snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr);
539
540 p = fdt_get_name(initial_boot_params, phy, &current_len);
541 if (p && current_len == strlen(new_name))
542 fdt_set_name(initial_boot_params, phy, new_name);
543 else
544 pr_err("Error: could not rename ethernet phy: <%s>", p);
545}
546
547static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac)
548{
549 u8 new_mac[6];
550 u64 mac = *pmac;
551 int r;
552
553 new_mac[0] = (mac >> 40) & 0xff;
554 new_mac[1] = (mac >> 32) & 0xff;
555 new_mac[2] = (mac >> 24) & 0xff;
556 new_mac[3] = (mac >> 16) & 0xff;
557 new_mac[4] = (mac >> 8) & 0xff;
558 new_mac[5] = mac & 0xff;
559
560 r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address",
561 new_mac, sizeof(new_mac));
562
563 if (r) {
564 pr_err("Setting \"local-mac-address\" failed %d", r);
565 return;
566 }
567 *pmac = mac + 1;
568}
569
570static void __init octeon_fdt_rm_ethernet(int node)
571{
572 const __be32 *phy_handle;
573
574 phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL);
575 if (phy_handle) {
576 u32 ph = be32_to_cpup(phy_handle);
577 int p = fdt_node_offset_by_phandle(initial_boot_params, ph);
578 if (p >= 0)
579 fdt_nop_node(initial_boot_params, p);
580 }
581 fdt_nop_node(initial_boot_params, node);
582}
583
584static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac)
585{
586 char name_buffer[20];
587 int eth;
588 int phy_addr;
589 int ipd_port;
590
591 snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p);
592 eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer);
593 if (eth < 0)
594 return;
595 if (p > max) {
596 pr_debug("Deleting port %x:%x\n", i, p);
597 octeon_fdt_rm_ethernet(eth);
598 return;
599 }
600 if (OCTEON_IS_MODEL(OCTEON_CN68XX))
601 ipd_port = (0x100 * i) + (0x10 * p) + 0x800;
602 else
603 ipd_port = 16 * i + p;
604
605 phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
606 octeon_fdt_set_phy(eth, phy_addr);
607 octeon_fdt_set_mac_addr(eth, pmac);
608}
609
610static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac)
611{
612 char name_buffer[20];
613 int iface;
614 int p;
615 int count;
616
617 count = cvmx_helper_interface_enumerate(idx);
618
619 snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx);
620 iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer);
621 if (iface < 0)
622 return;
623
624 for (p = 0; p < 16; p++)
625 octeon_fdt_pip_port(iface, idx, p, count - 1, pmac);
626}
627
628int __init octeon_prune_device_tree(void)
629{
630 int i, max_port, uart_mask;
631 const char *pip_path;
632 const char *alias_prop;
633 char name_buffer[20];
634 int aliases;
635 u64 mac_addr_base;
636
637 if (fdt_check_header(initial_boot_params))
638 panic("Corrupt Device Tree.");
639
640 aliases = fdt_path_offset(initial_boot_params, "/aliases");
641 if (aliases < 0) {
642 pr_err("Error: No /aliases node in device tree.");
643 return -EINVAL;
644 }
645
646
647 mac_addr_base =
648 ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 |
649 ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 |
650 ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 |
651 ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 |
652 ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 |
653 (octeon_bootinfo->mac_addr_base[5] & 0xffull);
654
655 if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
656 max_port = 2;
657 else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX))
658 max_port = 1;
659 else
660 max_port = 0;
661
662 if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E)
663 max_port = 0;
664
665 for (i = 0; i < 2; i++) {
666 int mgmt;
667 snprintf(name_buffer, sizeof(name_buffer),
668 "mix%d", i);
669 alias_prop = fdt_getprop(initial_boot_params, aliases,
670 name_buffer, NULL);
671 if (alias_prop) {
672 mgmt = fdt_path_offset(initial_boot_params, alias_prop);
673 if (mgmt < 0)
674 continue;
675 if (i >= max_port) {
676 pr_debug("Deleting mix%d\n", i);
677 octeon_fdt_rm_ethernet(mgmt);
678 fdt_nop_property(initial_boot_params, aliases,
679 name_buffer);
680 } else {
681 int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i);
682 octeon_fdt_set_phy(mgmt, phy_addr);
683 octeon_fdt_set_mac_addr(mgmt, &mac_addr_base);
684 }
685 }
686 }
687
688 pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL);
689 if (pip_path) {
690 int pip = fdt_path_offset(initial_boot_params, pip_path);
691 if (pip >= 0)
692 for (i = 0; i <= 4; i++)
693 octeon_fdt_pip_iface(pip, i, &mac_addr_base);
694 }
695
696 /* I2C */
697 if (OCTEON_IS_MODEL(OCTEON_CN52XX) ||
698 OCTEON_IS_MODEL(OCTEON_CN63XX) ||
699 OCTEON_IS_MODEL(OCTEON_CN68XX) ||
700 OCTEON_IS_MODEL(OCTEON_CN56XX))
701 max_port = 2;
702 else
703 max_port = 1;
704
705 for (i = 0; i < 2; i++) {
706 int i2c;
707 snprintf(name_buffer, sizeof(name_buffer),
708 "twsi%d", i);
709 alias_prop = fdt_getprop(initial_boot_params, aliases,
710 name_buffer, NULL);
711
712 if (alias_prop) {
713 i2c = fdt_path_offset(initial_boot_params, alias_prop);
714 if (i2c < 0)
715 continue;
716 if (i >= max_port) {
717 pr_debug("Deleting twsi%d\n", i);
718 fdt_nop_node(initial_boot_params, i2c);
719 fdt_nop_property(initial_boot_params, aliases,
720 name_buffer);
721 }
722 }
723 }
724
725 /* SMI/MDIO */
726 if (OCTEON_IS_MODEL(OCTEON_CN68XX))
727 max_port = 4;
728 else if (OCTEON_IS_MODEL(OCTEON_CN52XX) ||
729 OCTEON_IS_MODEL(OCTEON_CN63XX) ||
730 OCTEON_IS_MODEL(OCTEON_CN56XX))
731 max_port = 2;
732 else
733 max_port = 1;
734
735 for (i = 0; i < 2; i++) {
736 int i2c;
737 snprintf(name_buffer, sizeof(name_buffer),
738 "smi%d", i);
739 alias_prop = fdt_getprop(initial_boot_params, aliases,
740 name_buffer, NULL);
741
742 if (alias_prop) {
743 i2c = fdt_path_offset(initial_boot_params, alias_prop);
744 if (i2c < 0)
745 continue;
746 if (i >= max_port) {
747 pr_debug("Deleting smi%d\n", i);
748 fdt_nop_node(initial_boot_params, i2c);
749 fdt_nop_property(initial_boot_params, aliases,
750 name_buffer);
751 }
752 }
753 }
754
755 /* Serial */
756 uart_mask = 3;
757
758 /* Right now CN52XX is the only chip with a third uart */
759 if (OCTEON_IS_MODEL(OCTEON_CN52XX))
760 uart_mask |= 4; /* uart2 */
761
762 for (i = 0; i < 3; i++) {
763 int uart;
764 snprintf(name_buffer, sizeof(name_buffer),
765 "uart%d", i);
766 alias_prop = fdt_getprop(initial_boot_params, aliases,
767 name_buffer, NULL);
768
769 if (alias_prop) {
770 uart = fdt_path_offset(initial_boot_params, alias_prop);
771 if (uart_mask & (1 << i))
772 continue;
773 pr_debug("Deleting uart%d\n", i);
774 fdt_nop_node(initial_boot_params, uart);
775 fdt_nop_property(initial_boot_params, aliases,
776 name_buffer);
777 }
778 }
779
780 /* Compact Flash */
781 alias_prop = fdt_getprop(initial_boot_params, aliases,
782 "cf0", NULL);
783 if (alias_prop) {
784 union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
785 unsigned long base_ptr, region_base, region_size;
786 unsigned long region1_base = 0;
787 unsigned long region1_size = 0;
788 int cs, bootbus;
789 bool is_16bit = false;
790 bool is_true_ide = false;
791 __be32 new_reg[6];
792 __be32 *ranges;
793 int len;
794
795 int cf = fdt_path_offset(initial_boot_params, alias_prop);
796 base_ptr = 0;
797 if (octeon_bootinfo->major_version == 1
798 && octeon_bootinfo->minor_version >= 1) {
799 if (octeon_bootinfo->compact_flash_common_base_addr)
800 base_ptr = octeon_bootinfo->compact_flash_common_base_addr;
801 } else {
802 base_ptr = 0x1d000800;
803 }
804
805 if (!base_ptr)
806 goto no_cf;
807
808 /* Find CS0 region. */
809 for (cs = 0; cs < 8; cs++) {
810 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
811 region_base = mio_boot_reg_cfg.s.base << 16;
812 region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
813 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
814 && base_ptr < region_base + region_size) {
815 is_16bit = mio_boot_reg_cfg.s.width;
816 break;
817 }
818 }
819 if (cs >= 7) {
820 /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */
821 goto no_cf;
822 }
823
824 if (!(base_ptr & 0xfffful)) {
825 /*
826 * Boot loader signals availability of DMA (true_ide
827 * mode) by setting low order bits of base_ptr to
828 * zero.
829 */
830
831 /* Asume that CS1 immediately follows. */
832 mio_boot_reg_cfg.u64 =
833 cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1));
834 region1_base = mio_boot_reg_cfg.s.base << 16;
835 region1_size = (mio_boot_reg_cfg.s.size + 1) << 16;
836 if (!mio_boot_reg_cfg.s.en)
837 goto no_cf;
838 is_true_ide = true;
839
840 } else {
841 fdt_nop_property(initial_boot_params, cf, "cavium,true-ide");
842 fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle");
843 if (!is_16bit) {
844 __be32 width = cpu_to_be32(8);
845 fdt_setprop_inplace(initial_boot_params, cf,
846 "cavium,bus-width", &width, sizeof(width));
847 }
848 }
849 new_reg[0] = cpu_to_be32(cs);
850 new_reg[1] = cpu_to_be32(0);
851 new_reg[2] = cpu_to_be32(0x10000);
852 new_reg[3] = cpu_to_be32(cs + 1);
853 new_reg[4] = cpu_to_be32(0);
854 new_reg[5] = cpu_to_be32(0x10000);
855 fdt_setprop_inplace(initial_boot_params, cf,
856 "reg", new_reg, sizeof(new_reg));
857
858 bootbus = fdt_parent_offset(initial_boot_params, cf);
859 if (bootbus < 0)
860 goto no_cf;
861 ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len);
862 if (!ranges || len < (5 * 8 * sizeof(__be32)))
863 goto no_cf;
864
865 ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32);
866 ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff);
867 ranges[(cs * 5) + 4] = cpu_to_be32(region_size);
868 if (is_true_ide) {
869 cs++;
870 ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32);
871 ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff);
872 ranges[(cs * 5) + 4] = cpu_to_be32(region1_size);
873 }
874 goto end_cf;
875no_cf:
876 fdt_nop_node(initial_boot_params, cf);
877
878end_cf:
879 ;
880 }
881
882 /* 8 char LED */
883 alias_prop = fdt_getprop(initial_boot_params, aliases,
884 "led0", NULL);
885 if (alias_prop) {
886 union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
887 unsigned long base_ptr, region_base, region_size;
888 int cs, bootbus;
889 __be32 new_reg[6];
890 __be32 *ranges;
891 int len;
892 int led = fdt_path_offset(initial_boot_params, alias_prop);
893
894 base_ptr = octeon_bootinfo->led_display_base_addr;
895 if (base_ptr == 0)
896 goto no_led;
897 /* Find CS0 region. */
898 for (cs = 0; cs < 8; cs++) {
899 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
900 region_base = mio_boot_reg_cfg.s.base << 16;
901 region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
902 if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
903 && base_ptr < region_base + region_size)
904 break;
905 }
906
907 if (cs > 7)
908 goto no_led;
909
910 new_reg[0] = cpu_to_be32(cs);
911 new_reg[1] = cpu_to_be32(0x20);
912 new_reg[2] = cpu_to_be32(0x20);
913 new_reg[3] = cpu_to_be32(cs);
914 new_reg[4] = cpu_to_be32(0);
915 new_reg[5] = cpu_to_be32(0x20);
916 fdt_setprop_inplace(initial_boot_params, led,
917 "reg", new_reg, sizeof(new_reg));
918
919 bootbus = fdt_parent_offset(initial_boot_params, led);
920 if (bootbus < 0)
921 goto no_led;
922 ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len);
923 if (!ranges || len < (5 * 8 * sizeof(__be32)))
924 goto no_led;
925
926 ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32);
927 ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff);
928 ranges[(cs * 5) + 4] = cpu_to_be32(region_size);
929 goto end_led;
930
931no_led:
932 fdt_nop_node(initial_boot_params, led);
933end_led:
934 ;
935 }
936
937 /* OHCI/UHCI USB */
938 alias_prop = fdt_getprop(initial_boot_params, aliases,
939 "uctl", NULL);
940 if (alias_prop) {
941 int uctl = fdt_path_offset(initial_boot_params, alias_prop);
942
943 if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) ||
944 octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) {
945 pr_debug("Deleting uctl\n");
946 fdt_nop_node(initial_boot_params, uctl);
947 fdt_nop_property(initial_boot_params, aliases, "uctl");
948 } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E ||
949 octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) {
950 /* Missing "refclk-type" defaults to crystal. */
951 fdt_nop_property(initial_boot_params, uctl, "refclk-type");
952 }
953 }
954
955 return 0;
956}
957
958static int __init octeon_publish_devices(void)
959{
960 return of_platform_bus_probe(NULL, octeon_ids, NULL);
961}
962device_initcall(octeon_publish_devices);
963
David Daney512254b2009-09-16 14:54:18 -0700964MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
965MODULE_LICENSE("GPL");
966MODULE_DESCRIPTION("Platform driver for Octeon SOC");