1970bde0985cfe9e0663e732540260140e1acc5c
[openwrt/svn-archive/archive.git] / target / linux / kirkwood / patches-3.10 / 0023-net-mv643xx_eth-add-DT-parsing-support.patch
1 From dd6cae3b60ee88b301f9325db144e70b5e12482e Mon Sep 17 00:00:00 2001
2 From: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
3 Date: Wed, 29 May 2013 21:32:48 +0200
4 Subject: [PATCH 23/29] net: mv643xx_eth: add DT parsing support
5
6 This adds device tree parsing support for the shared driver of mv643xx_eth.
7 As the bindings are slightly different from current PPC bindings new binding
8 documentation is also added. Following PPC-style device setup, the shared
9 driver now also adds port platform_devices and sets up port platform_data.
10
11 Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
12 ---
13 .../devicetree/bindings/net/marvell-orion-net.txt | 85 ++++++++++++
14 drivers/net/ethernet/marvell/mv643xx_eth.c | 153 ++++++++++++++++++++-
15 2 files changed, 234 insertions(+), 4 deletions(-)
16 create mode 100644 Documentation/devicetree/bindings/net/marvell-orion-net.txt
17
18 diff --git a/Documentation/devicetree/bindings/net/marvell-orion-net.txt b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
19 new file mode 100644
20 index 0000000..a73b79f
21 --- /dev/null
22 +++ b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
23 @@ -0,0 +1,85 @@
24 +Marvell Orion/Discovery ethernet controller
25 +=============================================
26 +
27 +The Marvell Discovery ethernet controller can be found on Marvell Orion SoCs
28 +(Kirkwood, Dove, Orion5x, and Discovery Innovation) and as part of Marvell
29 +Discovery system controller chips (mv64[345]60).
30 +
31 +The Discovery ethernet controller is described with two levels of nodes. The
32 +first level describes the ethernet controller itself and the second level
33 +describes up to 3 ethernet port nodes within that controller. The reason for
34 +the multiple levels is that the port registers are interleaved within a single
35 +set of controller registers. Each port node describes port-specific properties.
36 +
37 +Note: The above separation is only true for Discovery system controllers.
38 +For Orion SoCs we stick to the separation, although there each controller has
39 +only one port associated. Multiple ports are implemented as multiple single-port
40 +controllers. As Kirkwood has some issues with proper initialization after reset,
41 +an extra compatible string is added for it.
42 +
43 +* Ethernet controller node
44 +
45 +Required controller properties:
46 + - #address-cells: shall be 1.
47 + - #size-cells: shall be 0.
48 + - compatible: shall be one of "marvell,orion-eth", "marvell,kirkwood-eth".
49 + - reg: address and length of the controller registers.
50 +
51 +Optional controller properties:
52 + - clocks: phandle reference to the controller clock.
53 + - marvell,tx-checksum-limit: max tx packet size for hardware checksum.
54 +
55 +* Ethernet port node
56 +
57 +Required port properties:
58 + - device_type: shall be "network".
59 + - compatible: shall be one of "marvell,orion-eth-port",
60 + "marvell,kirkwood-eth-port".
61 + - reg: port number relative to ethernet controller, shall be 0, 1, or 2.
62 + - interrupts: port interrupt.
63 + - local-mac-address: 6 bytes MAC address.
64 +
65 +Optional port properties:
66 + - marvell,tx-queue-size: size of the transmit ring buffer.
67 + - marvell,tx-sram-addr: address of transmit descriptor buffer located in SRAM.
68 + - marvell,tx-sram-size: size of transmit descriptor buffer located in SRAM.
69 + - marvell,rx-queue-size: size of the receive ring buffer.
70 + - marvell,rx-sram-addr: address of receive descriptor buffer located in SRAM.
71 + - marvell,rx-sram-size: size of receive descriptor buffer located in SRAM.
72 +
73 +and
74 +
75 + - phy-handle: phandle reference to ethernet PHY.
76 +
77 +or
78 +
79 + - speed: port speed if no PHY connected.
80 + - duplex: port mode if no PHY connected.
81 +
82 +* Node example:
83 +
84 +mdio-bus {
85 + ...
86 + ethphy: ethernet-phy@8 {
87 + device_type = "ethernet-phy";
88 + ...
89 + };
90 +};
91 +
92 +eth: ethernet-controller@72000 {
93 + compatible = "marvell,orion-eth";
94 + #address-cells = <1>;
95 + #size-cells = <0>;
96 + reg = <0x72000 0x2000>;
97 + clocks = <&gate_clk 2>;
98 + marvell,tx-checksum-limit = <1600>;
99 +
100 + ethernet@0 {
101 + device_type = "network";
102 + compatible = "marvell,orion-eth-port";
103 + reg = <0>;
104 + interrupts = <29>;
105 + phy-handle = <&ethphy>;
106 + local-mac-address = [00 00 00 00 00 00];
107 + };
108 +};
109 diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
110 index af6bdcc..004a250 100644
111 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c
112 +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
113 @@ -60,6 +60,9 @@
114 #include <linux/types.h>
115 #include <linux/slab.h>
116 #include <linux/clk.h>
117 +#include <linux/of.h>
118 +#include <linux/of_irq.h>
119 +#include <linux/of_net.h>
120 #include <linux/of_mdio.h>
121
122 static char mv643xx_eth_driver_name[] = "mv643xx_eth";
123 @@ -2453,13 +2456,148 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp)
124 }
125 }
126
127 +#if defined(CONFIG_OF)
128 +static const struct of_device_id mv643xx_eth_shared_ids[] = {
129 + { .compatible = "marvell,orion-eth", },
130 + { .compatible = "marvell,kirkwood-eth", },
131 + { }
132 +};
133 +MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
134 +#endif
135 +
136 +#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60)
137 +#define mv643xx_eth_property(_np, _name, _v) \
138 + do { \
139 + u32 tmp; \
140 + if (!of_property_read_u32(_np, "marvell," _name, &tmp)) \
141 + _v = tmp; \
142 + } while (0)
143 +
144 +static struct platform_device *port_platdev[3];
145 +
146 +static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
147 + struct device_node *pnp)
148 +{
149 + struct platform_device *ppdev;
150 + struct mv643xx_eth_platform_data ppd;
151 + struct resource res;
152 + const char *mac_addr;
153 + int ret;
154 +
155 + memset(&ppd, 0, sizeof(ppd));
156 + ppd.shared = pdev;
157 +
158 + memset(&res, 0, sizeof(res));
159 + if (!of_irq_to_resource(pnp, 0, &res)) {
160 + dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
161 + return -EINVAL;
162 + }
163 +
164 + if (of_property_read_u32(pnp, "reg", &ppd.port_number)) {
165 + dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name);
166 + return -EINVAL;
167 + }
168 +
169 + if (ppd.port_number >= 3) {
170 + dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name);
171 + return -EINVAL;
172 + }
173 +
174 + mac_addr = of_get_mac_address(pnp);
175 + if (mac_addr)
176 + memcpy(ppd.mac_addr, mac_addr, 6);
177 +
178 + mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
179 + mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
180 + mv643xx_eth_property(pnp, "tx-sram-size", ppd.tx_sram_size);
181 + mv643xx_eth_property(pnp, "rx-queue-size", ppd.rx_queue_size);
182 + mv643xx_eth_property(pnp, "rx-sram-addr", ppd.rx_sram_addr);
183 + mv643xx_eth_property(pnp, "rx-sram-size", ppd.rx_sram_size);
184 +
185 + ppd.phy_node = of_parse_phandle(pnp, "phy-handle", 0);
186 + if (!ppd.phy_node) {
187 + ppd.phy_addr = MV643XX_ETH_PHY_NONE;
188 + of_property_read_u32(pnp, "speed", &ppd.speed);
189 + of_property_read_u32(pnp, "duplex", &ppd.duplex);
190 + }
191 +
192 + ppdev = platform_device_alloc(MV643XX_ETH_NAME, ppd.port_number);
193 + if (!ppdev)
194 + return -ENOMEM;
195 + ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
196 +
197 + ret = platform_device_add_resources(ppdev, &res, 1);
198 + if (ret)
199 + goto port_err;
200 +
201 + ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd));
202 + if (ret)
203 + goto port_err;
204 +
205 + ret = platform_device_add(ppdev);
206 + if (ret)
207 + goto port_err;
208 +
209 + port_platdev[ppd.port_number] = ppdev;
210 +
211 + return 0;
212 +
213 +port_err:
214 + platform_device_put(ppdev);
215 + return ret;
216 +}
217 +
218 +static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
219 +{
220 + struct mv643xx_eth_shared_platform_data *pd;
221 + struct device_node *pnp, *np = pdev->dev.of_node;
222 + int ret;
223 +
224 + /* bail out if not registered from DT */
225 + if (!np)
226 + return 0;
227 +
228 + pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
229 + if (!pd)
230 + return -ENOMEM;
231 + pdev->dev.platform_data = pd;
232 +
233 + mv643xx_eth_property(np, "tx-checksum-limit", pd->tx_csum_limit);
234 +
235 + for_each_available_child_of_node(np, pnp) {
236 + ret = mv643xx_eth_shared_of_add_port(pdev, pnp);
237 + if (ret)
238 + return ret;
239 + }
240 + return 0;
241 +}
242 +
243 +static void mv643xx_eth_shared_of_remove(void)
244 +{
245 + int n;
246 +
247 + for (n = 0; n < 3; n++) {
248 + platform_device_del(port_platdev[n]);
249 + port_platdev[n] = NULL;
250 + }
251 +}
252 +#else
253 +static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
254 +{
255 + return 0
256 +}
257 +
258 +#define mv643xx_eth_shared_of_remove()
259 +#endif
260 +
261 static int mv643xx_eth_shared_probe(struct platform_device *pdev)
262 {
263 static int mv643xx_eth_version_printed;
264 - struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
265 + struct mv643xx_eth_shared_platform_data *pd;
266 struct mv643xx_eth_shared_private *msp;
267 const struct mbus_dram_target_info *dram;
268 struct resource *res;
269 + int ret;
270
271 if (!mv643xx_eth_version_printed++)
272 pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n",
273 @@ -2472,6 +2610,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
274 msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL);
275 if (msp == NULL)
276 return -ENOMEM;
277 + platform_set_drvdata(pdev, msp);
278
279 msp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
280 if (msp->base == NULL)
281 @@ -2488,12 +2627,15 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
282 if (dram)
283 mv643xx_eth_conf_mbus_windows(msp, dram);
284
285 + ret = mv643xx_eth_shared_of_probe(pdev);
286 + if (ret)
287 + return ret;
288 + pd = pdev->dev.platform_data;
289 +
290 msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
291 pd->tx_csum_limit : 9 * 1024;
292 infer_hw_params(msp);
293
294 - platform_set_drvdata(pdev, msp);
295 -
296 return 0;
297 }
298
299 @@ -2501,9 +2643,9 @@ static int mv643xx_eth_shared_remove(struct platform_device *pdev)
300 {
301 struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);
302
303 + mv643xx_eth_shared_of_remove();
304 if (!IS_ERR(msp->clk))
305 clk_disable_unprepare(msp->clk);
306 -
307 return 0;
308 }
309
310 @@ -2513,6 +2655,7 @@ static struct platform_driver mv643xx_eth_shared_driver = {
311 .driver = {
312 .name = MV643XX_ETH_SHARED_NAME,
313 .owner = THIS_MODULE,
314 + .of_match_table = of_match_ptr(mv643xx_eth_shared_ids),
315 },
316 };
317
318 @@ -2721,6 +2864,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
319 if (!IS_ERR(mp->clk)) {
320 clk_prepare_enable(mp->clk);
321 mp->t_clk = clk_get_rate(mp->clk);
322 + } else if (!IS_ERR(mp->shared->clk)) {
323 + mp->t_clk = clk_get_rate(mp->shared->clk);
324 }
325
326 set_params(mp, pd);
327 --
328 1.8.4.rc1
329