diff options
Diffstat (limited to 'arch/powerpc/sysdev/fsl_soc.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 281 |
1 files changed, 276 insertions, 5 deletions
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 92ba378b7990..022ed275ea68 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -3,6 +3,9 @@ | |||
3 | * | 3 | * |
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | 4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) |
5 | * | 5 | * |
6 | * 2006 (c) MontaVista Software, Inc. | ||
7 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
8 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 10 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; either version 2 of the License, or (at your | 11 | * Free Software Foundation; either version 2 of the License, or (at your |
@@ -20,15 +23,20 @@ | |||
20 | #include <linux/device.h> | 23 | #include <linux/device.h> |
21 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
22 | #include <linux/fsl_devices.h> | 25 | #include <linux/fsl_devices.h> |
26 | #include <linux/fs_enet_pd.h> | ||
27 | #include <linux/fs_uart_pd.h> | ||
23 | 28 | ||
24 | #include <asm/system.h> | 29 | #include <asm/system.h> |
25 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
26 | #include <asm/io.h> | 31 | #include <asm/io.h> |
27 | #include <asm/irq.h> | 32 | #include <asm/irq.h> |
33 | #include <asm/time.h> | ||
28 | #include <asm/prom.h> | 34 | #include <asm/prom.h> |
29 | #include <sysdev/fsl_soc.h> | 35 | #include <sysdev/fsl_soc.h> |
30 | #include <mm/mmu_decl.h> | 36 | #include <mm/mmu_decl.h> |
37 | #include <asm/cpm2.h> | ||
31 | 38 | ||
39 | extern void init_fcc_ioports(struct fs_platform_info*); | ||
32 | static phys_addr_t immrbase = -1; | 40 | static phys_addr_t immrbase = -1; |
33 | 41 | ||
34 | phys_addr_t get_immrbase(void) | 42 | phys_addr_t get_immrbase(void) |
@@ -42,7 +50,9 @@ phys_addr_t get_immrbase(void) | |||
42 | if (soc) { | 50 | if (soc) { |
43 | unsigned int size; | 51 | unsigned int size; |
44 | const void *prop = get_property(soc, "reg", &size); | 52 | const void *prop = get_property(soc, "reg", &size); |
45 | immrbase = of_translate_address(soc, prop); | 53 | |
54 | if (prop) | ||
55 | immrbase = of_translate_address(soc, prop); | ||
46 | of_node_put(soc); | 56 | of_node_put(soc); |
47 | }; | 57 | }; |
48 | 58 | ||
@@ -51,6 +61,59 @@ phys_addr_t get_immrbase(void) | |||
51 | 61 | ||
52 | EXPORT_SYMBOL(get_immrbase); | 62 | EXPORT_SYMBOL(get_immrbase); |
53 | 63 | ||
64 | #ifdef CONFIG_CPM2 | ||
65 | |||
66 | static u32 brgfreq = -1; | ||
67 | |||
68 | u32 get_brgfreq(void) | ||
69 | { | ||
70 | struct device_node *node; | ||
71 | |||
72 | if (brgfreq != -1) | ||
73 | return brgfreq; | ||
74 | |||
75 | node = of_find_node_by_type(NULL, "cpm"); | ||
76 | if (node) { | ||
77 | unsigned int size; | ||
78 | const unsigned int *prop = get_property(node, "brg-frequency", | ||
79 | &size); | ||
80 | |||
81 | if (prop) | ||
82 | brgfreq = *prop; | ||
83 | of_node_put(node); | ||
84 | }; | ||
85 | |||
86 | return brgfreq; | ||
87 | } | ||
88 | |||
89 | EXPORT_SYMBOL(get_brgfreq); | ||
90 | |||
91 | static u32 fs_baudrate = -1; | ||
92 | |||
93 | u32 get_baudrate(void) | ||
94 | { | ||
95 | struct device_node *node; | ||
96 | |||
97 | if (fs_baudrate != -1) | ||
98 | return fs_baudrate; | ||
99 | |||
100 | node = of_find_node_by_type(NULL, "serial"); | ||
101 | if (node) { | ||
102 | unsigned int size; | ||
103 | const unsigned int *prop = get_property(node, "current-speed", | ||
104 | &size); | ||
105 | |||
106 | if (prop) | ||
107 | fs_baudrate = *prop; | ||
108 | of_node_put(node); | ||
109 | }; | ||
110 | |||
111 | return fs_baudrate; | ||
112 | } | ||
113 | |||
114 | EXPORT_SYMBOL(get_baudrate); | ||
115 | #endif /* CONFIG_CPM2 */ | ||
116 | |||
54 | static int __init gfar_mdio_of_init(void) | 117 | static int __init gfar_mdio_of_init(void) |
55 | { | 118 | { |
56 | struct device_node *np; | 119 | struct device_node *np; |
@@ -85,8 +148,11 @@ static int __init gfar_mdio_of_init(void) | |||
85 | mdio_data.irq[k] = -1; | 148 | mdio_data.irq[k] = -1; |
86 | 149 | ||
87 | while ((child = of_get_next_child(np, child)) != NULL) { | 150 | while ((child = of_get_next_child(np, child)) != NULL) { |
88 | const u32 *id = get_property(child, "reg", NULL); | 151 | int irq = irq_of_parse_and_map(child, 0); |
89 | mdio_data.irq[*id] = irq_of_parse_and_map(child, 0); | 152 | if (irq != NO_IRQ) { |
153 | const u32 *id = get_property(child, "reg", NULL); | ||
154 | mdio_data.irq[*id] = irq; | ||
155 | } | ||
90 | } | 156 | } |
91 | 157 | ||
92 | ret = | 158 | ret = |
@@ -128,7 +194,7 @@ static int __init gfar_of_init(void) | |||
128 | const char *model; | 194 | const char *model; |
129 | const void *mac_addr; | 195 | const void *mac_addr; |
130 | const phandle *ph; | 196 | const phandle *ph; |
131 | int n_res = 1; | 197 | int n_res = 2; |
132 | 198 | ||
133 | memset(r, 0, sizeof(r)); | 199 | memset(r, 0, sizeof(r)); |
134 | memset(&gfar_data, 0, sizeof(gfar_data)); | 200 | memset(&gfar_data, 0, sizeof(gfar_data)); |
@@ -159,7 +225,7 @@ static int __init gfar_of_init(void) | |||
159 | 225 | ||
160 | gfar_dev = | 226 | gfar_dev = |
161 | platform_device_register_simple("fsl-gianfar", i, &r[0], | 227 | platform_device_register_simple("fsl-gianfar", i, &r[0], |
162 | n_res + 1); | 228 | n_res); |
163 | 229 | ||
164 | if (IS_ERR(gfar_dev)) { | 230 | if (IS_ERR(gfar_dev)) { |
165 | ret = PTR_ERR(gfar_dev); | 231 | ret = PTR_ERR(gfar_dev); |
@@ -478,3 +544,208 @@ err: | |||
478 | } | 544 | } |
479 | 545 | ||
480 | arch_initcall(fsl_usb_of_init); | 546 | arch_initcall(fsl_usb_of_init); |
547 | |||
548 | #ifdef CONFIG_CPM2 | ||
549 | |||
550 | static const char fcc_regs[] = "fcc_regs"; | ||
551 | static const char fcc_regs_c[] = "fcc_regs_c"; | ||
552 | static const char fcc_pram[] = "fcc_pram"; | ||
553 | static char bus_id[9][BUS_ID_SIZE]; | ||
554 | |||
555 | static int __init fs_enet_of_init(void) | ||
556 | { | ||
557 | struct device_node *np; | ||
558 | unsigned int i; | ||
559 | struct platform_device *fs_enet_dev; | ||
560 | struct resource res; | ||
561 | int ret; | ||
562 | |||
563 | for (np = NULL, i = 0; | ||
564 | (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL; | ||
565 | i++) { | ||
566 | struct resource r[4]; | ||
567 | struct device_node *phy, *mdio; | ||
568 | struct fs_platform_info fs_enet_data; | ||
569 | const unsigned int *id, *phy_addr; | ||
570 | const void *mac_addr; | ||
571 | const phandle *ph; | ||
572 | const char *model; | ||
573 | |||
574 | memset(r, 0, sizeof(r)); | ||
575 | memset(&fs_enet_data, 0, sizeof(fs_enet_data)); | ||
576 | |||
577 | ret = of_address_to_resource(np, 0, &r[0]); | ||
578 | if (ret) | ||
579 | goto err; | ||
580 | r[0].name = fcc_regs; | ||
581 | |||
582 | ret = of_address_to_resource(np, 1, &r[1]); | ||
583 | if (ret) | ||
584 | goto err; | ||
585 | r[1].name = fcc_pram; | ||
586 | |||
587 | ret = of_address_to_resource(np, 2, &r[2]); | ||
588 | if (ret) | ||
589 | goto err; | ||
590 | r[2].name = fcc_regs_c; | ||
591 | |||
592 | r[3].start = r[3].end = irq_of_parse_and_map(np, 0); | ||
593 | r[3].flags = IORESOURCE_IRQ; | ||
594 | |||
595 | fs_enet_dev = | ||
596 | platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4); | ||
597 | |||
598 | if (IS_ERR(fs_enet_dev)) { | ||
599 | ret = PTR_ERR(fs_enet_dev); | ||
600 | goto err; | ||
601 | } | ||
602 | |||
603 | model = get_property(np, "model", NULL); | ||
604 | if (model == NULL) { | ||
605 | ret = -ENODEV; | ||
606 | goto unreg; | ||
607 | } | ||
608 | |||
609 | mac_addr = get_property(np, "mac-address", NULL); | ||
610 | memcpy(fs_enet_data.macaddr, mac_addr, 6); | ||
611 | |||
612 | ph = get_property(np, "phy-handle", NULL); | ||
613 | phy = of_find_node_by_phandle(*ph); | ||
614 | |||
615 | if (phy == NULL) { | ||
616 | ret = -ENODEV; | ||
617 | goto unreg; | ||
618 | } | ||
619 | |||
620 | phy_addr = get_property(phy, "reg", NULL); | ||
621 | fs_enet_data.phy_addr = *phy_addr; | ||
622 | |||
623 | id = get_property(np, "device-id", NULL); | ||
624 | fs_enet_data.fs_no = *id; | ||
625 | strcpy(fs_enet_data.fs_type, model); | ||
626 | |||
627 | mdio = of_get_parent(phy); | ||
628 | ret = of_address_to_resource(mdio, 0, &res); | ||
629 | if (ret) { | ||
630 | of_node_put(phy); | ||
631 | of_node_put(mdio); | ||
632 | goto unreg; | ||
633 | } | ||
634 | |||
635 | fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL)); | ||
636 | fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); | ||
637 | |||
638 | if (strstr(model, "FCC")) { | ||
639 | int fcc_index = *id - 1; | ||
640 | |||
641 | fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); | ||
642 | fs_enet_data.rx_ring = 32; | ||
643 | fs_enet_data.tx_ring = 32; | ||
644 | fs_enet_data.rx_copybreak = 240; | ||
645 | fs_enet_data.use_napi = 0; | ||
646 | fs_enet_data.napi_weight = 17; | ||
647 | fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index); | ||
648 | fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index); | ||
649 | fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index); | ||
650 | |||
651 | snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x", | ||
652 | (u32)res.start, fs_enet_data.phy_addr); | ||
653 | fs_enet_data.bus_id = (char*)&bus_id[(*id)]; | ||
654 | fs_enet_data.init_ioports = init_fcc_ioports; | ||
655 | } | ||
656 | |||
657 | of_node_put(phy); | ||
658 | of_node_put(mdio); | ||
659 | |||
660 | ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, | ||
661 | sizeof(struct | ||
662 | fs_platform_info)); | ||
663 | if (ret) | ||
664 | goto unreg; | ||
665 | } | ||
666 | return 0; | ||
667 | |||
668 | unreg: | ||
669 | platform_device_unregister(fs_enet_dev); | ||
670 | err: | ||
671 | return ret; | ||
672 | } | ||
673 | |||
674 | arch_initcall(fs_enet_of_init); | ||
675 | |||
676 | static const char scc_regs[] = "regs"; | ||
677 | static const char scc_pram[] = "pram"; | ||
678 | |||
679 | static int __init cpm_uart_of_init(void) | ||
680 | { | ||
681 | struct device_node *np; | ||
682 | unsigned int i; | ||
683 | struct platform_device *cpm_uart_dev; | ||
684 | int ret; | ||
685 | |||
686 | for (np = NULL, i = 0; | ||
687 | (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL; | ||
688 | i++) { | ||
689 | struct resource r[3]; | ||
690 | struct fs_uart_platform_info cpm_uart_data; | ||
691 | const int *id; | ||
692 | const char *model; | ||
693 | |||
694 | memset(r, 0, sizeof(r)); | ||
695 | memset(&cpm_uart_data, 0, sizeof(cpm_uart_data)); | ||
696 | |||
697 | ret = of_address_to_resource(np, 0, &r[0]); | ||
698 | if (ret) | ||
699 | goto err; | ||
700 | |||
701 | r[0].name = scc_regs; | ||
702 | |||
703 | ret = of_address_to_resource(np, 1, &r[1]); | ||
704 | if (ret) | ||
705 | goto err; | ||
706 | r[1].name = scc_pram; | ||
707 | |||
708 | r[2].start = r[2].end = irq_of_parse_and_map(np, 0); | ||
709 | r[2].flags = IORESOURCE_IRQ; | ||
710 | |||
711 | cpm_uart_dev = | ||
712 | platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3); | ||
713 | |||
714 | if (IS_ERR(cpm_uart_dev)) { | ||
715 | ret = PTR_ERR(cpm_uart_dev); | ||
716 | goto err; | ||
717 | } | ||
718 | |||
719 | id = get_property(np, "device-id", NULL); | ||
720 | cpm_uart_data.fs_no = *id; | ||
721 | |||
722 | model = (char*)get_property(np, "model", NULL); | ||
723 | strcpy(cpm_uart_data.fs_type, model); | ||
724 | |||
725 | cpm_uart_data.uart_clk = ppc_proc_freq; | ||
726 | |||
727 | cpm_uart_data.tx_num_fifo = 4; | ||
728 | cpm_uart_data.tx_buf_size = 32; | ||
729 | cpm_uart_data.rx_num_fifo = 4; | ||
730 | cpm_uart_data.rx_buf_size = 32; | ||
731 | cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL)); | ||
732 | cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL)); | ||
733 | |||
734 | ret = | ||
735 | platform_device_add_data(cpm_uart_dev, &cpm_uart_data, | ||
736 | sizeof(struct | ||
737 | fs_uart_platform_info)); | ||
738 | if (ret) | ||
739 | goto unreg; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | |||
744 | unreg: | ||
745 | platform_device_unregister(cpm_uart_dev); | ||
746 | err: | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | arch_initcall(cpm_uart_of_init); | ||
751 | #endif /* CONFIG_CPM2 */ | ||