diff options
author | Vitaly Bordug <vbordug@ru.mvista.com> | 2006-09-21 09:26:34 -0400 |
---|---|---|
committer | Vitaly Bordug <vbordug@ru.mvista.com> | 2006-09-21 09:26:34 -0400 |
commit | fba43665360d361d338efd120a34ad615ca960d8 (patch) | |
tree | e1dcc1f4948a4d4c2051b1b344bd5bdf26a55d0b /arch/powerpc/sysdev/fsl_soc.c | |
parent | 7dcd86e14319f4ceab883787ab2e00a5f860d14d (diff) |
POWERPC: Add cpm2 stuff support to the fsl_soc.c
This patch contains necessary modifications to support the CPM2 SoC peripherals.
For the time being, those are fs_enet Ethernet driver and cpm_uart serial.
Written initially to support mpc8560, it also suites to the part of the large PQ2
(more specifically, mpc8260) family.
Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
Diffstat (limited to 'arch/powerpc/sysdev/fsl_soc.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 268 |
1 files changed, 263 insertions, 5 deletions
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 92ba378b7990..0ed2aaee105c 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,14 +23,18 @@ | |||
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 | ||
32 | static phys_addr_t immrbase = -1; | 39 | static phys_addr_t immrbase = -1; |
33 | 40 | ||
@@ -42,7 +49,9 @@ phys_addr_t get_immrbase(void) | |||
42 | if (soc) { | 49 | if (soc) { |
43 | unsigned int size; | 50 | unsigned int size; |
44 | const void *prop = get_property(soc, "reg", &size); | 51 | const void *prop = get_property(soc, "reg", &size); |
45 | immrbase = of_translate_address(soc, prop); | 52 | |
53 | if (prop) | ||
54 | immrbase = of_translate_address(soc, prop); | ||
46 | of_node_put(soc); | 55 | of_node_put(soc); |
47 | }; | 56 | }; |
48 | 57 | ||
@@ -51,6 +60,59 @@ phys_addr_t get_immrbase(void) | |||
51 | 60 | ||
52 | EXPORT_SYMBOL(get_immrbase); | 61 | EXPORT_SYMBOL(get_immrbase); |
53 | 62 | ||
63 | #ifdef CONFIG_CPM2 | ||
64 | |||
65 | static u32 brgfreq = -1; | ||
66 | |||
67 | u32 get_brgfreq(void) | ||
68 | { | ||
69 | struct device_node *node; | ||
70 | |||
71 | if (brgfreq != -1) | ||
72 | return brgfreq; | ||
73 | |||
74 | node = of_find_node_by_type(NULL, "cpm"); | ||
75 | if (node) { | ||
76 | unsigned int size; | ||
77 | const unsigned int *prop = get_property(node, "brg-frequency", | ||
78 | &size); | ||
79 | |||
80 | if (prop) | ||
81 | brgfreq = *prop; | ||
82 | of_node_put(node); | ||
83 | }; | ||
84 | |||
85 | return brgfreq; | ||
86 | } | ||
87 | |||
88 | EXPORT_SYMBOL(get_brgfreq); | ||
89 | |||
90 | static u32 fs_baudrate = -1; | ||
91 | |||
92 | u32 get_baudrate(void) | ||
93 | { | ||
94 | struct device_node *node; | ||
95 | |||
96 | if (fs_baudrate != -1) | ||
97 | return fs_baudrate; | ||
98 | |||
99 | node = of_find_node_by_type(NULL, "serial"); | ||
100 | if (node) { | ||
101 | unsigned int size; | ||
102 | const unsigned int *prop = get_property(node, "current-speed", | ||
103 | &size); | ||
104 | |||
105 | if (prop) | ||
106 | fs_baudrate = *prop; | ||
107 | of_node_put(node); | ||
108 | }; | ||
109 | |||
110 | return fs_baudrate; | ||
111 | } | ||
112 | |||
113 | EXPORT_SYMBOL(get_baudrate); | ||
114 | #endif /* CONFIG_CPM2 */ | ||
115 | |||
54 | static int __init gfar_mdio_of_init(void) | 116 | static int __init gfar_mdio_of_init(void) |
55 | { | 117 | { |
56 | struct device_node *np; | 118 | struct device_node *np; |
@@ -85,8 +147,11 @@ static int __init gfar_mdio_of_init(void) | |||
85 | mdio_data.irq[k] = -1; | 147 | mdio_data.irq[k] = -1; |
86 | 148 | ||
87 | while ((child = of_get_next_child(np, child)) != NULL) { | 149 | while ((child = of_get_next_child(np, child)) != NULL) { |
88 | const u32 *id = get_property(child, "reg", NULL); | 150 | int irq = irq_of_parse_and_map(child, 0); |
89 | mdio_data.irq[*id] = irq_of_parse_and_map(child, 0); | 151 | if (irq != NO_IRQ) { |
152 | const u32 *id = get_property(child, "reg", NULL); | ||
153 | mdio_data.irq[*id] = irq; | ||
154 | } | ||
90 | } | 155 | } |
91 | 156 | ||
92 | ret = | 157 | ret = |
@@ -128,7 +193,7 @@ static int __init gfar_of_init(void) | |||
128 | const char *model; | 193 | const char *model; |
129 | const void *mac_addr; | 194 | const void *mac_addr; |
130 | const phandle *ph; | 195 | const phandle *ph; |
131 | int n_res = 1; | 196 | int n_res = 2; |
132 | 197 | ||
133 | memset(r, 0, sizeof(r)); | 198 | memset(r, 0, sizeof(r)); |
134 | memset(&gfar_data, 0, sizeof(gfar_data)); | 199 | memset(&gfar_data, 0, sizeof(gfar_data)); |
@@ -159,7 +224,7 @@ static int __init gfar_of_init(void) | |||
159 | 224 | ||
160 | gfar_dev = | 225 | gfar_dev = |
161 | platform_device_register_simple("fsl-gianfar", i, &r[0], | 226 | platform_device_register_simple("fsl-gianfar", i, &r[0], |
162 | n_res + 1); | 227 | n_res); |
163 | 228 | ||
164 | if (IS_ERR(gfar_dev)) { | 229 | if (IS_ERR(gfar_dev)) { |
165 | ret = PTR_ERR(gfar_dev); | 230 | ret = PTR_ERR(gfar_dev); |
@@ -478,3 +543,196 @@ err: | |||
478 | } | 543 | } |
479 | 544 | ||
480 | arch_initcall(fsl_usb_of_init); | 545 | arch_initcall(fsl_usb_of_init); |
546 | |||
547 | #ifdef CONFIG_CPM2 | ||
548 | |||
549 | static const char fcc_regs[] = "fcc_regs"; | ||
550 | static const char fcc_regs_c[] = "fcc_regs_c"; | ||
551 | static const char fcc_pram[] = "fcc_pram"; | ||
552 | static char bus_id[9][BUS_ID_SIZE]; | ||
553 | |||
554 | static int __init fs_enet_of_init(void) | ||
555 | { | ||
556 | struct device_node *np; | ||
557 | unsigned int i; | ||
558 | struct platform_device *fs_enet_dev; | ||
559 | struct resource res; | ||
560 | int ret; | ||
561 | |||
562 | for (np = NULL, i = 0; | ||
563 | (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL; | ||
564 | i++) { | ||
565 | struct resource r[4]; | ||
566 | struct device_node *phy, *mdio; | ||
567 | struct fs_platform_info fs_enet_data; | ||
568 | const unsigned int *id, *phy_addr; | ||
569 | const void *mac_addr; | ||
570 | const phandle *ph; | ||
571 | const char *model; | ||
572 | |||
573 | memset(r, 0, sizeof(r)); | ||
574 | memset(&fs_enet_data, 0, sizeof(fs_enet_data)); | ||
575 | |||
576 | ret = of_address_to_resource(np, 0, &r[0]); | ||
577 | if (ret) | ||
578 | goto err; | ||
579 | r[0].name = fcc_regs; | ||
580 | |||
581 | ret = of_address_to_resource(np, 1, &r[1]); | ||
582 | if (ret) | ||
583 | goto err; | ||
584 | r[1].name = fcc_pram; | ||
585 | |||
586 | ret = of_address_to_resource(np, 2, &r[2]); | ||
587 | if (ret) | ||
588 | goto err; | ||
589 | r[2].name = fcc_regs_c; | ||
590 | |||
591 | r[3].start = r[3].end = irq_of_parse_and_map(np, 0); | ||
592 | r[3].flags = IORESOURCE_IRQ; | ||
593 | |||
594 | fs_enet_dev = | ||
595 | platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4); | ||
596 | |||
597 | if (IS_ERR(fs_enet_dev)) { | ||
598 | ret = PTR_ERR(fs_enet_dev); | ||
599 | goto err; | ||
600 | } | ||
601 | |||
602 | model = get_property(np, "model", NULL); | ||
603 | if (model == NULL) { | ||
604 | ret = -ENODEV; | ||
605 | goto unreg; | ||
606 | } | ||
607 | |||
608 | mac_addr = get_property(np, "mac-address", NULL); | ||
609 | memcpy(fs_enet_data.macaddr, mac_addr, 6); | ||
610 | |||
611 | ph = get_property(np, "phy-handle", NULL); | ||
612 | phy = of_find_node_by_phandle(*ph); | ||
613 | |||
614 | if (phy == NULL) { | ||
615 | ret = -ENODEV; | ||
616 | goto unreg; | ||
617 | } | ||
618 | |||
619 | phy_addr = get_property(phy, "reg", NULL); | ||
620 | fs_enet_data.phy_addr = *phy_addr; | ||
621 | |||
622 | id = get_property(np, "device-id", NULL); | ||
623 | fs_enet_data.fs_no = *id; | ||
624 | |||
625 | mdio = of_get_parent(phy); | ||
626 | ret = of_address_to_resource(mdio, 0, &res); | ||
627 | if (ret) { | ||
628 | of_node_put(phy); | ||
629 | of_node_put(mdio); | ||
630 | goto unreg; | ||
631 | } | ||
632 | |||
633 | if (strstr(model, "FCC")) { | ||
634 | int fcc_index = fs_get_fcc_index(*id); | ||
635 | |||
636 | fs_enet_data.dpram_offset = (u32)cpm2_immr->im_dprambase; | ||
637 | fs_enet_data.rx_ring = 32; | ||
638 | fs_enet_data.tx_ring = 32; | ||
639 | fs_enet_data.rx_copybreak = 240; | ||
640 | fs_enet_data.use_napi = 0; | ||
641 | fs_enet_data.napi_weight = 17; | ||
642 | fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index); | ||
643 | fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index); | ||
644 | fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index); | ||
645 | |||
646 | snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x", | ||
647 | (u32)res.start, fs_enet_data.phy_addr); | ||
648 | fs_enet_data.bus_id = (char*)&bus_id[(*id)]; | ||
649 | } | ||
650 | |||
651 | of_node_put(phy); | ||
652 | of_node_put(mdio); | ||
653 | |||
654 | ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, | ||
655 | sizeof(struct | ||
656 | fs_platform_info)); | ||
657 | if (ret) | ||
658 | goto unreg; | ||
659 | } | ||
660 | return 0; | ||
661 | |||
662 | unreg: | ||
663 | platform_device_unregister(fs_enet_dev); | ||
664 | err: | ||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | arch_initcall(fs_enet_of_init); | ||
669 | |||
670 | static const char scc_regs[] = "regs"; | ||
671 | static const char scc_pram[] = "pram"; | ||
672 | |||
673 | static int __init cpm_uart_of_init(void) | ||
674 | { | ||
675 | struct device_node *np; | ||
676 | unsigned int i; | ||
677 | struct platform_device *cpm_uart_dev; | ||
678 | int ret; | ||
679 | |||
680 | for (np = NULL, i = 0; | ||
681 | (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL; | ||
682 | i++) { | ||
683 | struct resource r[3]; | ||
684 | struct fs_uart_platform_info cpm_uart_data; | ||
685 | const int *id; | ||
686 | |||
687 | memset(r, 0, sizeof(r)); | ||
688 | memset(&cpm_uart_data, 0, sizeof(cpm_uart_data)); | ||
689 | |||
690 | ret = of_address_to_resource(np, 0, &r[0]); | ||
691 | if (ret) | ||
692 | goto err; | ||
693 | |||
694 | r[0].name = scc_regs; | ||
695 | |||
696 | ret = of_address_to_resource(np, 1, &r[1]); | ||
697 | if (ret) | ||
698 | goto err; | ||
699 | r[1].name = scc_pram; | ||
700 | |||
701 | r[2].start = r[2].end = irq_of_parse_and_map(np, 0); | ||
702 | r[2].flags = IORESOURCE_IRQ; | ||
703 | |||
704 | cpm_uart_dev = | ||
705 | platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3); | ||
706 | |||
707 | if (IS_ERR(cpm_uart_dev)) { | ||
708 | ret = PTR_ERR(cpm_uart_dev); | ||
709 | goto err; | ||
710 | } | ||
711 | |||
712 | id = get_property(np, "device-id", NULL); | ||
713 | cpm_uart_data.fs_no = *id; | ||
714 | cpm_uart_data.uart_clk = ppc_proc_freq; | ||
715 | |||
716 | cpm_uart_data.tx_num_fifo = 4; | ||
717 | cpm_uart_data.tx_buf_size = 32; | ||
718 | cpm_uart_data.rx_num_fifo = 4; | ||
719 | cpm_uart_data.rx_buf_size = 32; | ||
720 | |||
721 | ret = | ||
722 | platform_device_add_data(cpm_uart_dev, &cpm_uart_data, | ||
723 | sizeof(struct | ||
724 | fs_uart_platform_info)); | ||
725 | if (ret) | ||
726 | goto unreg; | ||
727 | } | ||
728 | |||
729 | return 0; | ||
730 | |||
731 | unreg: | ||
732 | platform_device_unregister(cpm_uart_dev); | ||
733 | err: | ||
734 | return ret; | ||
735 | } | ||
736 | |||
737 | arch_initcall(cpm_uart_of_init); | ||
738 | #endif /* CONFIG_CPM2 */ | ||