Commit | Line | Data |
---|---|---|
2b9d7467 ZR |
1 | /* |
2 | * tsi108/109 device setup code | |
3 | * | |
4 | * Maintained by Roy Zang < tie-fei.zang@freescale.com > | |
5 | * | |
6 | * 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 | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. | |
10 | */ | |
11 | ||
2b9d7467 ZR |
12 | #include <linux/stddef.h> |
13 | #include <linux/kernel.h> | |
14 | #include <linux/init.h> | |
15 | #include <linux/errno.h> | |
16 | #include <linux/major.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/irq.h> | |
4b16f8e2 | 19 | #include <linux/export.h> |
2b9d7467 ZR |
20 | #include <linux/device.h> |
21 | #include <linux/platform_device.h> | |
4b6ba8aa | 22 | #include <linux/of_net.h> |
2b9d7467 ZR |
23 | #include <asm/tsi108.h> |
24 | ||
25 | #include <asm/system.h> | |
60063497 | 26 | #include <linux/atomic.h> |
2b9d7467 ZR |
27 | #include <asm/io.h> |
28 | #include <asm/irq.h> | |
29 | #include <asm/prom.h> | |
30 | #include <mm/mmu_decl.h> | |
31 | ||
32 | #undef DEBUG | |
33 | ||
34 | #ifdef DEBUG | |
35 | #define DBG(fmt...) do { printk(fmt); } while(0) | |
36 | #else | |
37 | #define DBG(fmt...) do { } while(0) | |
38 | #endif | |
39 | ||
40 | static phys_addr_t tsi108_csr_base = -1; | |
41 | ||
42 | phys_addr_t get_csrbase(void) | |
43 | { | |
44 | struct device_node *tsi; | |
45 | ||
46 | if (tsi108_csr_base != -1) | |
47 | return tsi108_csr_base; | |
48 | ||
49 | tsi = of_find_node_by_type(NULL, "tsi-bridge"); | |
50 | if (tsi) { | |
51 | unsigned int size; | |
e2eb6392 | 52 | const void *prop = of_get_property(tsi, "reg", &size); |
2b9d7467 ZR |
53 | tsi108_csr_base = of_translate_address(tsi, prop); |
54 | of_node_put(tsi); | |
55 | }; | |
56 | return tsi108_csr_base; | |
57 | } | |
58 | ||
59 | u32 get_vir_csrbase(void) | |
60 | { | |
61 | return (u32) (ioremap(get_csrbase(), 0x10000)); | |
62 | } | |
63 | ||
64 | EXPORT_SYMBOL(get_csrbase); | |
65 | EXPORT_SYMBOL(get_vir_csrbase); | |
66 | ||
67 | static int __init tsi108_eth_of_init(void) | |
68 | { | |
69 | struct device_node *np; | |
26cb7d8b | 70 | unsigned int i = 0; |
2b9d7467 ZR |
71 | struct platform_device *tsi_eth_dev; |
72 | struct resource res; | |
73 | int ret; | |
74 | ||
26cb7d8b | 75 | for_each_compatible_node(np, "network", "tsi108-ethernet") { |
2b9d7467 | 76 | struct resource r[2]; |
e58ca3de | 77 | struct device_node *phy, *mdio; |
2b9d7467 | 78 | hw_info tsi_eth_data; |
e2eb6392 | 79 | const unsigned int *phy_id; |
c3386e40 | 80 | const void *mac_addr; |
e2eb6392 | 81 | const phandle *ph; |
2b9d7467 ZR |
82 | |
83 | memset(r, 0, sizeof(r)); | |
84 | memset(&tsi_eth_data, 0, sizeof(tsi_eth_data)); | |
85 | ||
86 | ret = of_address_to_resource(np, 0, &r[0]); | |
518fdae2 JP |
87 | DBG("%s: name:start->end = %s:%pR\n", |
88 | __func__, r[0].name, &r[0]); | |
2b9d7467 ZR |
89 | if (ret) |
90 | goto err; | |
91 | ||
92 | r[1].name = "tx"; | |
c4342ff9 ZR |
93 | r[1].start = irq_of_parse_and_map(np, 0); |
94 | r[1].end = irq_of_parse_and_map(np, 0); | |
2b9d7467 | 95 | r[1].flags = IORESOURCE_IRQ; |
518fdae2 JP |
96 | DBG("%s: name:start->end = %s:%pR\n", |
97 | __func__, r[1].name, &r[1]); | |
2b9d7467 ZR |
98 | |
99 | tsi_eth_dev = | |
26cb7d8b | 100 | platform_device_register_simple("tsi-ethernet", i++, &r[0], |
c4342ff9 | 101 | 1); |
2b9d7467 ZR |
102 | |
103 | if (IS_ERR(tsi_eth_dev)) { | |
104 | ret = PTR_ERR(tsi_eth_dev); | |
105 | goto err; | |
106 | } | |
107 | ||
c1b78d05 JB |
108 | mac_addr = of_get_mac_address(np); |
109 | if (mac_addr) | |
110 | memcpy(tsi_eth_data.mac_addr, mac_addr, 6); | |
2b9d7467 | 111 | |
e58ca3de DG |
112 | ph = of_get_property(np, "mdio-handle", NULL); |
113 | mdio = of_find_node_by_phandle(*ph); | |
114 | ret = of_address_to_resource(mdio, 0, &res); | |
115 | of_node_put(mdio); | |
116 | if (ret) | |
117 | goto unreg; | |
118 | ||
e2eb6392 | 119 | ph = of_get_property(np, "phy-handle", NULL); |
2b9d7467 ZR |
120 | phy = of_find_node_by_phandle(*ph); |
121 | ||
122 | if (phy == NULL) { | |
123 | ret = -ENODEV; | |
124 | goto unreg; | |
125 | } | |
126 | ||
e58ca3de DG |
127 | phy_id = of_get_property(phy, "reg", NULL); |
128 | ||
2b9d7467 ZR |
129 | tsi_eth_data.regs = r[0].start; |
130 | tsi_eth_data.phyregs = res.start; | |
131 | tsi_eth_data.phy = *phy_id; | |
c4342ff9 | 132 | tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0); |
e58ca3de DG |
133 | |
134 | /* Some boards with the TSI108 bridge (e.g. Holly) | |
135 | * have a miswiring of the ethernet PHYs which | |
136 | * requires a workaround. The special | |
137 | * "txc-rxc-delay-disable" property enables this | |
138 | * workaround. FIXME: Need to port the tsi108_eth | |
139 | * driver itself to phylib and use a non-misleading | |
140 | * name for the workaround flag - it's not actually to | |
141 | * do with the model of PHY in use */ | |
142 | if (of_get_property(phy, "txc-rxc-delay-disable", NULL)) | |
c1b78d05 | 143 | tsi_eth_data.phy_type = TSI108_PHY_BCM54XX; |
2b9d7467 | 144 | of_node_put(phy); |
e58ca3de | 145 | |
2b9d7467 ZR |
146 | ret = |
147 | platform_device_add_data(tsi_eth_dev, &tsi_eth_data, | |
148 | sizeof(hw_info)); | |
149 | if (ret) | |
150 | goto unreg; | |
151 | } | |
152 | return 0; | |
153 | unreg: | |
154 | platform_device_unregister(tsi_eth_dev); | |
155 | err: | |
26cb7d8b | 156 | of_node_put(np); |
2b9d7467 ZR |
157 | return ret; |
158 | } | |
159 | ||
160 | arch_initcall(tsi108_eth_of_init); |